/* * Public domain source code. * * Author: * Joseph "looncraz" Groover */ #include #include #include #include #include #include #include #include #include #define B_TRANSLATION_CONTEXT "Default decorator about box" namespace BPrivate { DecorInfo::DecorInfo() : fVersion(0), fModificationTime(0), fInitStatus(B_NO_INIT) { } DecorInfo::DecorInfo(const BString& path) : fPath(path), fVersion(0), fModificationTime(0), fInitStatus(B_NO_INIT) { BEntry entry(path.String(), true); entry.GetRef(&fRef); _Init(); } DecorInfo::DecorInfo(const entry_ref& ref) : fRef(ref), fVersion(0), fModificationTime(0), fInitStatus(B_NO_INIT) { BPath path(&ref); fPath = path.Path(); _Init(); } DecorInfo::~DecorInfo() { } status_t DecorInfo::SetTo(const entry_ref& ref) { Unset(); BPath path(&ref); fPath = path.Path(); fRef = ref; _Init(); return InitCheck(); } status_t DecorInfo::SetTo(BString path) { BEntry entry(path.String(), true); entry_ref ref; entry.GetRef(&ref); return SetTo(ref); } status_t DecorInfo::InitCheck() const { return fInitStatus; } void DecorInfo::Unset() { fRef = entry_ref(); fPath = ""; fName = ""; fAuthors = ""; fShortDescription = ""; fLicenseURL = ""; fLicenseName = ""; fSupportURL = ""; fVersion = 0; fModificationTime = 0; fInitStatus = B_NO_INIT; } bool DecorInfo::IsDefault() const { return fPath == "Default"; } BString DecorInfo::Path() const { return fPath; } const entry_ref* DecorInfo::Ref() const { if (InitCheck() != B_OK || IsDefault()) return NULL; return &fRef; } BString DecorInfo::Name() const { return fName; } BString DecorInfo::ShortcutName() const { if (IsDefault()) return "Default"; else if (Ref() != NULL) return fRef.name; return fName; } BString DecorInfo::Authors() const { return fAuthors; } BString DecorInfo::ShortDescription() const { return fShortDescription; } BString DecorInfo::LongDescription() const { return fLongDescription; } BString DecorInfo::LicenseURL() const { return fLicenseURL; } BString DecorInfo::LicenseName() const { return fLicenseName; } BString DecorInfo::SupportURL() const { return fSupportURL; } float DecorInfo::Version() const { return fVersion; } time_t DecorInfo::ModificationTime() const { return fModificationTime; } bool DecorInfo::CheckForChanges(bool& deleted) { if (InitCheck() != B_OK) return false; BEntry entry(&fRef); if (entry.InitCheck() != B_OK) return false; if (!entry.Exists()) { deleted = true; return true; } time_t modtime = 0; if (entry.GetModificationTime(&modtime) != B_OK) { fprintf(stderr, "DecorInfo::CheckForChanges()\tERROR: " "BEntry:GetModificationTime() failed\n"); return false; } if (fModificationTime != modtime) { _Init(true); return true; } return false; } void DecorInfo::_Init(bool isUpdate) { if (!isUpdate && InitCheck() != B_NO_INIT) { // TODO: remove after validation fprintf(stderr, "DecorInfo::_Init()\tImproper init state\n"); return; } BEntry entry; if (fPath == "Default") { if (isUpdate) { // should never happen fprintf(stderr, "DecorInfo::_Init(true)\tBUG BUG updating default" "decorator!?!?!\n"); return; } fAuthors = "DarkWyrm, Stephan Aßmus, Clemens Zeidler, Ingo Weinhold"; fLongDescription = ""; fLicenseURL = "http://"; fLicenseName = "MIT"; fSupportURL = "http://www.haiku-os.org/"; fVersion = 0.5; fInitStatus = B_OK; fName = gSystemCatalog.GetString(B_TRANSLATE_MARK("Default"), B_TRANSLATION_CONTEXT); fShortDescription = gSystemCatalog.GetString(B_TRANSLATE_MARK( "Default Haiku window decorator."), B_TRANSLATION_CONTEXT); // The following is to get the modification time of the app_server // and, thusly, the Default decorator... // If you can make it more simple, please do! BPath path; find_directory(B_SYSTEM_SERVERS_DIRECTORY, &path); path.Append("app_server"); entry.SetTo(path.Path(), true); if (!entry.Exists()) { fprintf(stderr, "Server MIA the world has become its slave! " "Call the CIA!\n"); return; } entry.GetModificationTime(&fModificationTime); return; } // Is a file system object... entry.SetTo(&fRef, true); // follow link if (entry.InitCheck() != B_OK) { fInitStatus = entry.InitCheck(); return; } if (!entry.Exists()) { if (isUpdate) { fprintf(stderr, "DecorInfo::_Init()\tERROR: decorator deleted" " after CheckForChanges() found it!\n"); fprintf(stderr, "DecorInfo::_Init()\tERROR: DecorInfo will " "Unset\n"); Unset(); } return; } // update fRef to match file system object entry.GetRef(&fRef); entry.GetModificationTime(&fModificationTime); BResources resources(&fRef); if (resources.InitCheck() != B_OK) { fprintf(stderr, "DecorInfo::_Init()\t BResource InitCheck() failure\n"); return; } size_t infoSize = 0; const void* infoData = resources.LoadResource(B_MESSAGE_TYPE, "be:decor:info", &infoSize); BMessage infoMessage; if (infoData == NULL || infoSize == 0 || infoMessage.Unflatten((const char*)infoData) != B_OK) { fprintf(stderr, "DecorInfo::_init()\tNo extended information found for" " \"%s\"\n", fRef.name); } else { infoMessage.FindString("name", &fName); infoMessage.FindString("authors", &fAuthors); infoMessage.FindString("short_descr", &fShortDescription); infoMessage.FindString("long_descr", &fLongDescription); infoMessage.FindString("lic_url", &fLicenseURL); infoMessage.FindString("lic_name", &fLicenseName); infoMessage.FindString("support_url", &fSupportURL); infoMessage.FindFloat ("version", &fVersion); } fInitStatus = B_OK; fName = fRef.name; } // #pragma mark - DecorInfoUtility DecorInfoUtility::DecorInfoUtility(bool scanNow) : fHasScanned(false) { // get default decorator from app_server DecorInfo* info = new(std::nothrow) DecorInfo("Default"); if (info == NULL || info->InitCheck() != B_OK) { delete info; fprintf(stderr, "DecorInfoUtility::constructor\tdefault decorator's " "DecorInfo failed InitCheck()\n"); return; } fList.AddItem(info); if (scanNow) ScanDecorators(); } DecorInfoUtility::~DecorInfoUtility() { BAutolock _(fLock); for (int i = fList.CountItems() - 1; i >= 0; --i) delete fList.ItemAt(i); } status_t DecorInfoUtility::ScanDecorators() { status_t result; BPath systemPath; result = find_directory(B_SYSTEM_ADDONS_DIRECTORY, &systemPath); if (result == B_OK) result = systemPath.Append("decorators"); if (result == B_OK) { BDirectory systemDirectory(systemPath.Path()); result = systemDirectory.InitCheck(); if (result == B_OK) { result = _ScanDecorators(systemDirectory); if (result != B_OK) { fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n", strerror(result)); return result; } } } BPath systemNonPackagedPath; result = find_directory(B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, &systemNonPackagedPath); if (result == B_OK) result = systemNonPackagedPath.Append("decorators"); if (result == B_OK) { BDirectory systemNonPackagedDirectory(systemNonPackagedPath.Path()); result = systemNonPackagedDirectory.InitCheck(); if (result == B_OK) { result = _ScanDecorators(systemNonPackagedDirectory); if (result != B_OK) { fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n", strerror(result)); return result; } } } BPath userPath; result = find_directory(B_USER_ADDONS_DIRECTORY, &userPath); if (result == B_OK) result = userPath.Append("decorators"); if (result == B_OK) { BDirectory userDirectory(userPath.Path()); result = userDirectory.InitCheck(); if (result == B_OK) { result = _ScanDecorators(userDirectory); if (result != B_OK) { fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n", strerror(result)); return result; } } } BPath userNonPackagedPath; result = find_directory(B_USER_NONPACKAGED_ADDONS_DIRECTORY, &userNonPackagedPath); if (result == B_OK) result = userNonPackagedPath.Append("decorators"); if (result == B_OK) { BDirectory userNonPackagedDirectory(userNonPackagedPath.Path()); result = userNonPackagedDirectory.InitCheck(); if (result == B_OK) { result = _ScanDecorators(userNonPackagedDirectory); if (result != B_OK) { fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tERROR: %s\n", strerror(result)); return result; } } } fHasScanned = true; return B_OK; } int32 DecorInfoUtility::CountDecorators() { BAutolock _(fLock); if (!fHasScanned) ScanDecorators(); return fList.CountItems(); } DecorInfo* DecorInfoUtility::DecoratorAt(int32 index) { BAutolock _(fLock); return fList.ItemAt(index); } DecorInfo* DecorInfoUtility::FindDecorator(const BString& string) { if (string.Length() == 0) return CurrentDecorator(); if (string == "Default") return DefaultDecorator(); BAutolock _(fLock); if (!fHasScanned) ScanDecorators(); // search by path DecorInfo* decor = _FindDecor(string); if (decor != NULL) return decor; // search by name for (int i = 1; i < fList.CountItems(); ++i) { decor = fList.ItemAt(i); if (string.ICompare(decor->Name()) == 0) return decor; } return NULL; } DecorInfo* DecorInfoUtility::CurrentDecorator() { BAutolock _(fLock); if (!fHasScanned) ScanDecorators(); BString name; get_decorator(name); return FindDecorator(name); } DecorInfo* DecorInfoUtility::DefaultDecorator() { BAutolock _(fLock); return fList.ItemAt(0); } bool DecorInfoUtility::IsCurrentDecorator(DecorInfo* decor) { BAutolock _(fLock); if (decor == NULL) return false; return decor->Path() == CurrentDecorator()->Path(); } status_t DecorInfoUtility::SetDecorator(DecorInfo* decor) { if (decor == NULL) return B_BAD_VALUE; BAutolock _(fLock); if (decor->IsDefault()) return set_decorator("Default"); return set_decorator(decor->Path()); } status_t DecorInfoUtility::SetDecorator(int32 index) { BAutolock _(fLock); if (!fHasScanned) return B_ERROR; DecorInfo* decor = DecoratorAt(index); if (decor == NULL) return B_BAD_INDEX; return SetDecorator(decor); } status_t DecorInfoUtility::Preview(DecorInfo* decor, BWindow* window) { if (decor == NULL) return B_BAD_VALUE; return preview_decorator(decor->Path(), window); } // #pargma mark - private DecorInfo* DecorInfoUtility::_FindDecor(const BString& pathString) { // find decor by path and path alone! if (!fLock.IsLocked()) { fprintf(stderr, "DecorInfoUtility::_find_decor()\tfailure to lock! - " "BUG BUG BUG\n"); return NULL; } if (pathString == "Default") return fList.ItemAt(0); for (int i = 1; i < fList.CountItems(); ++i) { DecorInfo* decor = fList.ItemAt(i); // Find the DecoratorInfo either by its true current location or by // what we still think the location is (before we had a chance to // update). NOTE: This will only catch the case when the user moved the // folder in which the add-on file lives. It will not work when the user // moves the add-on file itself or renames it. BPath path(decor->Ref()); if (path.Path() == pathString || decor->Path() == pathString) return decor; } return NULL; } status_t DecorInfoUtility::_ScanDecorators(BDirectory decoratorDirectory) { BAutolock _(fLock); // First, run through our list and DecorInfos CheckForChanges() if (fHasScanned) { for (int i = fList.CountItems() - 1; i > 0; --i) { DecorInfo* decorInfo = fList.ItemAt(i); bool deleted = false; decorInfo->CheckForChanges(deleted); if (deleted) { fList.RemoveItem(decorInfo); delete decorInfo; } } } entry_ref ref; // Now, look at file system, skip the entries for which we already have // a DecorInfo in the list. while (decoratorDirectory.GetNextRef(&ref) == B_OK) { BPath path(&decoratorDirectory); status_t result = path.Append(ref.name); if (result != B_OK) { fprintf(stderr, "DecorInfoUtility::_ScanDecorators()\tFailed to" "append decorator file to path, skipping: %s.\n", strerror(result)); continue; } if (_FindDecor(path.Path()) != NULL) continue; DecorInfo* decorInfo = new(std::nothrow) DecorInfo(ref); if (decorInfo == NULL || decorInfo->InitCheck() != B_OK) { fprintf(stderr, "DecorInfoUtility::_ScanDecorators()\tInitCheck() " "failure on decorator, skipping.\n"); delete decorInfo; continue; } fList.AddItem(decorInfo); } return B_OK; } } // namespace BPrivate