hrev44898 adds 2 changesets to branch 'master' old head: 2510baa4685f8f570c607ceedfd73473d69342c4 new head: 52cdfde04b346aa33eaebd4063321b80683973aa overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=52cdfde+%5E2510baa ---------------------------------------------------------------------------- a22e8c6: Cleanup: respect 80 chars/line limit. 52cdfde: Fix relying on order of static object destruction in Locale Kit. * use only a single static object (MutableLocaleRoster) instead of two, which avoids any problems if the order of static object destruction would destroy RosterData before MutableLocaleRoster * rename BPrivate::RosterData to BPrivate::LocaleRosterData and move it into a header and implementation file of its own This should hopefully fix problems encountered with a clang-compiled Locale Kit. [ Oliver Tappe <zooey@xxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- 8 files changed, 900 insertions(+), 846 deletions(-) headers/os/locale/LocaleRoster.h | 16 +- headers/private/locale/LocaleRosterData.h | 142 +++++ headers/private/locale/MutableLocaleRoster.h | 107 ---- src/kits/locale/Jamfile | 1 + src/kits/locale/Locale.cpp | 3 +- src/kits/locale/LocaleRoster.cpp | 87 ++- src/kits/locale/LocaleRosterData.cpp | 682 ++++++++++++++++++++++ src/kits/locale/MutableLocaleRoster.cpp | 708 +---------------------- ############################################################################ Commit: a22e8c6fe28437bc4b4036d1388282e1f5a756e4 URL: http://cgit.haiku-os.org/haiku/commit/?id=a22e8c6 Author: Oliver Tappe <zooey@xxxxxxxxxxxxxxx> Date: Sat Nov 24 14:03:01 2012 UTC Cleanup: respect 80 chars/line limit. ---------------------------------------------------------------------------- diff --git a/src/kits/locale/MutableLocaleRoster.cpp b/src/kits/locale/MutableLocaleRoster.cpp index 2b4d606..6689dd2 100644 --- a/src/kits/locale/MutableLocaleRoster.cpp +++ b/src/kits/locale/MutableLocaleRoster.cpp @@ -724,7 +724,8 @@ MutableLocaleRoster::Default() status_t -MutableLocaleRoster::SetDefaultFormattingConventions(const BFormattingConventions& newFormattingConventions) +MutableLocaleRoster::SetDefaultFormattingConventions( + const BFormattingConventions& newFormattingConventions) { return RosterData::Default()->SetDefaultFormattingConventions( newFormattingConventions); ############################################################################ Revision: hrev44898 Commit: 52cdfde04b346aa33eaebd4063321b80683973aa URL: http://cgit.haiku-os.org/haiku/commit/?id=52cdfde Author: Oliver Tappe <zooey@xxxxxxxxxxxxxxx> Date: Mon Nov 26 00:18:57 2012 UTC Fix relying on order of static object destruction in Locale Kit. * use only a single static object (MutableLocaleRoster) instead of two, which avoids any problems if the order of static object destruction would destroy RosterData before MutableLocaleRoster * rename BPrivate::RosterData to BPrivate::LocaleRosterData and move it into a header and implementation file of its own This should hopefully fix problems encountered with a clang-compiled Locale Kit. ---------------------------------------------------------------------------- diff --git a/headers/os/locale/LocaleRoster.h b/headers/os/locale/LocaleRoster.h index 8e77e59..fab2469 100644 --- a/headers/os/locale/LocaleRoster.h +++ b/headers/os/locale/LocaleRoster.h @@ -21,14 +21,19 @@ class BMessage; class BTimeZone; +namespace BPrivate { + class LocaleRosterData; +} + + enum { B_LOCALE_CHANGED = '_LCC', }; class BLocaleRoster { + public: - BLocaleRoster(); ~BLocaleRoster(); static BLocaleRoster* Default(); @@ -70,6 +75,8 @@ public: // Get the catalog for the calling image // (that needs to link with liblocalestub.a) + const BLocale* GetDefaultLocale() const; + bool IsFilesystemTranslationPreferred() const; status_t GetLocalizedFileName(BString& localizedFileName, @@ -83,6 +90,12 @@ public: static const char* kEmbeddedCatAttr; static int32 kEmbeddedCatResId; +protected: + BLocaleRoster(); + +protected: + BPrivate::LocaleRosterData* fData; + private: static BCatalog* _GetCatalog(BCatalog* catalog, vint32* catalogInitStatus); @@ -90,6 +103,7 @@ private: status_t _PrepareCatalogEntry(const entry_ref& ref, BString& signature, BString& context, BString& string, bool traverse); + }; diff --git a/headers/private/locale/LocaleRosterData.h b/headers/private/locale/LocaleRosterData.h new file mode 100644 index 0000000..6e84bde --- /dev/null +++ b/headers/private/locale/LocaleRosterData.h @@ -0,0 +1,142 @@ +/* + * Copyright 2010-2012, Haiku. All rights reserved. + * Distributed under the terms of the MIT license. + */ +#ifndef _LOCALE_ROSTER_DATA_H_ +#define _LOCALE_ROSTER_DATA_H_ + + +#include <Collator.h> +#include <FormattingConventions.h> +#include <image.h> +#include <Language.h> +#include <List.h> +#include <Locale.h> +#include <Locker.h> +#include <Message.h> +#include <Resources.h> +#include <TimeZone.h> + + +class BCatalogData; +class BLocale; + +struct entry_ref; + + +namespace BPrivate { + + +/* + * Struct containing the actual locale data. + */ +struct LocaleRosterData { + BLocker fLock; + BList fCatalogAddOnInfos; + BMessage fPreferredLanguages; + + BLocale fDefaultLocale; + BTimeZone fDefaultTimeZone; + + bool fIsFilesystemTranslationPreferred; + + LocaleRosterData(const BLanguage& language, + const BFormattingConventions& conventions); + ~LocaleRosterData(); + + status_t InitCheck() const; + + status_t Refresh(); + + static int CompareInfos(const void* left, + const void* right); + + status_t GetResources(BResources** resources); + + status_t SetDefaultFormattingConventions( + const BFormattingConventions& convetions); + status_t SetDefaultTimeZone(const BTimeZone& zone); + status_t SetPreferredLanguages(const BMessage* msg); + status_t SetFilesystemTranslationPreferred( + bool preferred); +private: + status_t _Initialize(); + + status_t _InitializeCatalogAddOns(); + void _CleanupCatalogAddOns(); + + status_t _LoadLocaleSettings(); + status_t _SaveLocaleSettings(); + + status_t _LoadTimeSettings(); + status_t _SaveTimeSettings(); + + status_t _SetDefaultFormattingConventions( + const BFormattingConventions& conventions); + status_t _SetDefaultTimeZone(const BTimeZone& zone); + status_t _SetPreferredLanguages(const BMessage* msg); + void _SetFilesystemTranslationPreferred( + bool preferred); + + status_t _AddDefaultFormattingConventionsToMessage( + BMessage* message) const; + status_t _AddDefaultTimeZoneToMessage( + BMessage* message) const; + status_t _AddPreferredLanguagesToMessage( + BMessage* message) const; + status_t _AddFilesystemTranslationPreferenceToMessage( + BMessage* message) const; + +private: + status_t fInitStatus; + + bool fAreResourcesLoaded; + BResources fResources; +}; + + +typedef BCatalogData* (*InstantiateCatalogFunc)(const entry_ref& catalogOwner, + const char* language, uint32 fingerprint); + +typedef BCatalogData* (*CreateCatalogFunc)(const char* name, + const char* language); + +typedef BCatalogData* (*InstantiateEmbeddedCatalogFunc)( + entry_ref* appOrAddOnRef); + +typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*, + const char*, int32); + + +/* + * info about a single catalog-add-on (representing a catalog type): + */ +struct CatalogAddOnInfo { + InstantiateCatalogFunc fInstantiateFunc; + CreateCatalogFunc fCreateFunc; + GetAvailableLanguagesFunc fLanguagesFunc; + + BString fName; + BString fPath; + image_id fAddOnImage; + uint8 fPriority; + BList fLoadedCatalogs; + bool fIsEmbedded; + // an embedded add-on actually isn't an + // add-on, it is included as part of the + // library. + // The DefaultCatalog is such a beast! + + CatalogAddOnInfo(const BString& name, + const BString& path, uint8 priority); + ~CatalogAddOnInfo(); + + bool MakeSureItsLoaded(); + void UnloadIfPossible(); +}; + + +} // namespace BPrivate + + +#endif // _LOCALE_ROSTER_DATA_H_ diff --git a/headers/private/locale/MutableLocaleRoster.h b/headers/private/locale/MutableLocaleRoster.h index 4eb072b..c4cd209 100644 --- a/headers/private/locale/MutableLocaleRoster.h +++ b/headers/private/locale/MutableLocaleRoster.h @@ -60,113 +60,6 @@ public: }; -typedef BCatalogData* (*InstantiateCatalogFunc)(const entry_ref& catalogOwner, - const char* language, uint32 fingerprint); - -typedef BCatalogData* (*CreateCatalogFunc)(const char* name, - const char* language); - -typedef BCatalogData* (*InstantiateEmbeddedCatalogFunc)( - entry_ref* appOrAddOnRef); - -typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*, - const char*, int32); - -/* - * info about a single catalog-add-on (representing a catalog type): - */ -struct CatalogAddOnInfo { - InstantiateCatalogFunc fInstantiateFunc; - CreateCatalogFunc fCreateFunc; - GetAvailableLanguagesFunc fLanguagesFunc; - - BString fName; - BString fPath; - image_id fAddOnImage; - uint8 fPriority; - BList fLoadedCatalogs; - bool fIsEmbedded; - // an embedded add-on actually isn't an - // add-on, it is included as part of the - // library. - // The DefaultCatalog is such a beast! - - CatalogAddOnInfo(const BString& name, - const BString& path, uint8 priority); - ~CatalogAddOnInfo(); - - bool MakeSureItsLoaded(); - void UnloadIfPossible(); -}; - - -/* - * The global data that is shared between all roster-objects of a process. - */ -struct RosterData { - BLocker fLock; - BList fCatalogAddOnInfos; - BMessage fPreferredLanguages; - - BLocale fDefaultLocale; - BTimeZone fDefaultTimeZone; - - bool fIsFilesystemTranslationPreferred; - - bool fAreResourcesLoaded; - BResources fResources; - - status_t fInitStatus; - - RosterData(const BLanguage& language, - const BFormattingConventions& conventions); - ~RosterData(); - - static RosterData* Default(); - - status_t InitCheck() const; - - status_t Refresh(); - - static int CompareInfos(const void* left, - const void* right); - - status_t SetDefaultFormattingConventions( - const BFormattingConventions& convetions); - status_t SetDefaultTimeZone(const BTimeZone& zone); - status_t SetPreferredLanguages(const BMessage* msg); - status_t SetFilesystemTranslationPreferred( - bool preferred); -private: - status_t _Initialize(); - - status_t _InitializeCatalogAddOns(); - void _CleanupCatalogAddOns(); - - status_t _LoadLocaleSettings(); - status_t _SaveLocaleSettings(); - - status_t _LoadTimeSettings(); - status_t _SaveTimeSettings(); - - status_t _SetDefaultFormattingConventions( - const BFormattingConventions& conventions); - status_t _SetDefaultTimeZone(const BTimeZone& zone); - status_t _SetPreferredLanguages(const BMessage* msg); - void _SetFilesystemTranslationPreferred( - bool preferred); - - status_t _AddDefaultFormattingConventionsToMessage( - BMessage* message) const; - status_t _AddDefaultTimeZoneToMessage( - BMessage* message) const; - status_t _AddPreferredLanguagesToMessage( - BMessage* message) const; - status_t _AddFilesystemTranslationPreferenceToMessage( - BMessage* message) const; -}; - - } // namespace BPrivate diff --git a/src/kits/locale/Jamfile b/src/kits/locale/Jamfile index 007f6e9..61ad69f 100644 --- a/src/kits/locale/Jamfile +++ b/src/kits/locale/Jamfile @@ -19,6 +19,7 @@ local sources = Language.cpp Locale.cpp LocaleRoster.cpp + LocaleRosterData.cpp MutableLocaleRoster.cpp TimeZone.cpp diff --git a/src/kits/locale/Locale.cpp b/src/kits/locale/Locale.cpp index b25a416..ed2b95e 100644 --- a/src/kits/locale/Locale.cpp +++ b/src/kits/locale/Locale.cpp @@ -14,7 +14,6 @@ #include <LanguagePrivate.h> #include <Locale.h> #include <LocaleRoster.h> -#include <MutableLocaleRoster.h> #include <TimeZone.h> #include <ICUWrapper.h> @@ -59,7 +58,7 @@ BLocale::BLocale(const BLocale& other) /*static*/ const BLocale* BLocale::Default() { - return &BPrivate::RosterData::Default()->fDefaultLocale; + return BLocaleRoster::Default()->GetDefaultLocale(); } diff --git a/src/kits/locale/LocaleRoster.cpp b/src/kits/locale/LocaleRoster.cpp index c4238b9..22d2961 100644 --- a/src/kits/locale/LocaleRoster.cpp +++ b/src/kits/locale/LocaleRoster.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010, Haiku. All rights reserved. + * Copyright 2003-2012, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -10,27 +10,23 @@ #include <LocaleRoster.h> +#include <assert.h> #include <ctype.h> -#include <set> -#include <assert.h> +#include <new> #include <Autolock.h> #include <Bitmap.h> #include <Catalog.h> -#include <Collator.h> -#include <DefaultCatalog.h> -#include <Directory.h> #include <Entry.h> -#include <File.h> #include <FormattingConventions.h> #include <fs_attr.h> #include <IconUtils.h> #include <Language.h> #include <Locale.h> +#include <LocaleRosterData.h> #include <MutableLocaleRoster.h> #include <Node.h> -#include <Path.h> #include <Roster.h> #include <String.h> #include <TimeZone.h> @@ -45,7 +41,6 @@ using BPrivate::CatalogAddOnInfo; using BPrivate::MutableLocaleRoster; -using BPrivate::RosterData; /* @@ -67,26 +62,6 @@ int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA; // this may live in an app- or add-on-file -static status_t -load_resources_if_needed(RosterData* rosterData) -{ - if (rosterData->fAreResourcesLoaded) - return B_OK; - - status_t result = rosterData->fResources.SetToImage( - (const void*)&BLocaleRoster::Default); - if (result != B_OK) - return result; - - result = rosterData->fResources.PreloadResourceType(); - if (result != B_OK) - return result; - - rosterData->fAreResourcesLoaded = true; - return B_OK; -} - - static const char* country_code_for_language(const BLanguage& language) { @@ -149,12 +124,16 @@ country_code_for_language(const BLanguage& language) BLocaleRoster::BLocaleRoster() + : + fData(new(std::nothrow) BPrivate::LocaleRosterData(BLanguage("en_US"), + BFormattingConventions("en_US"))) { } BLocaleRoster::~BLocaleRoster() { + delete fData; } @@ -168,7 +147,7 @@ BLocaleRoster::Default() status_t BLocaleRoster::Refresh() { - return RosterData::Default()->Refresh(); + return fData->Refresh(); } @@ -178,17 +157,22 @@ BLocaleRoster::GetDefaultTimeZone(BTimeZone* timezone) const if (!timezone) return B_BAD_VALUE; - RosterData* rosterData = RosterData::Default(); - BAutolock lock(rosterData->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return B_ERROR; - *timezone = rosterData->fDefaultTimeZone; + *timezone = fData->fDefaultTimeZone; return B_OK; } +const BLocale* +BLocaleRoster::GetDefaultLocale() const +{ + return &fData->fDefaultLocale; +} + status_t BLocaleRoster::GetLanguage(const char* languageCode, BLanguage** _language) const @@ -211,12 +195,11 @@ BLocaleRoster::GetPreferredLanguages(BMessage* languages) const if (!languages) return B_BAD_VALUE; - RosterData* rosterData = RosterData::Default(); - BAutolock lock(rosterData->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return B_ERROR; - *languages = rosterData->fPreferredLanguages; + *languages = fData->fPreferredLanguages; return B_OK; } @@ -367,12 +350,12 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode) if (countryCode == NULL) return B_BAD_VALUE; - RosterData* rosterData = RosterData::Default(); - BAutolock lock(rosterData->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return B_ERROR; - status_t status = load_resources_if_needed(rosterData); + BResources* resources; + status_t status = fData->GetResources(&resources); if (status != B_OK) return status; @@ -389,8 +372,8 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode) normalizedCode[2] = '\0'; size_t size; - const void* buffer = rosterData->fResources.LoadResource( - B_VECTOR_ICON_TYPE, normalizedCode, &size); + const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE, + normalizedCode, &size); if (buffer == NULL || size == 0) return B_NAME_NOT_FOUND; @@ -407,12 +390,12 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon, || languageCode[1] == '\0') return B_BAD_VALUE; - RosterData* rosterData = RosterData::Default(); - BAutolock lock(rosterData->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return B_ERROR; - status_t status = load_resources_if_needed(rosterData); + BResources* resources; + status_t status = fData->GetResources(&resources); if (status != B_OK) return status; @@ -424,8 +407,8 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon, normalizedCode[2] = '\0'; size_t size; - const void* buffer = rosterData->fResources.LoadResource( - B_VECTOR_ICON_TYPE, normalizedCode, &size); + const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE, + normalizedCode, &size); if (buffer != NULL && size != 0) { return BIconUtils::GetVectorIcon(static_cast<const uint8*>(buffer), size, flagIcon); @@ -450,15 +433,14 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList, if (languageList == NULL) return B_BAD_VALUE; - RosterData* rosterData = RosterData::Default(); - BAutolock lock(rosterData->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return B_ERROR; - int32 count = rosterData->fCatalogAddOnInfos.CountItems(); + int32 count = fData->fCatalogAddOnInfos.CountItems(); for (int32 i = 0; i < count; ++i) { CatalogAddOnInfo* info - = (CatalogAddOnInfo*)rosterData->fCatalogAddOnInfos.ItemAt(i); + = (CatalogAddOnInfo*)fData->fCatalogAddOnInfos.ItemAt(i); if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc) continue; @@ -474,12 +456,11 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList, bool BLocaleRoster::IsFilesystemTranslationPreferred() const { - RosterData* rosterData = RosterData::Default(); - BAutolock lock(rosterData->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return B_ERROR; - return rosterData->fIsFilesystemTranslationPreferred; + return fData->fIsFilesystemTranslationPreferred; } diff --git a/src/kits/locale/LocaleRosterData.cpp b/src/kits/locale/LocaleRosterData.cpp new file mode 100644 index 0000000..d87b01b --- /dev/null +++ b/src/kits/locale/LocaleRosterData.cpp @@ -0,0 +1,682 @@ +/* + * Copyright 2003-2012, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel DÃrfler, axeld@xxxxxxxxxxxxxxxx + * Oliver Tappe, zooey@xxxxxxxxxxxxxxx + */ + + +#include <LocaleRosterData.h> + +#include <Autolock.h> +#include <Catalog.h> +#include <Collator.h> +#include <Debug.h> +#include <DefaultCatalog.h> +#include <Directory.h> +#include <Entry.h> +#include <File.h> +#include <FindDirectory.h> +#include <FormattingConventions.h> +#include <Language.h> +#include <Locale.h> +#include <Node.h> +#include <Path.h> +#include <Roster.h> +#include <String.h> +#include <TimeZone.h> + +// ICU includes +#include <unicode/locid.h> +#include <unicode/timezone.h> + + +namespace BPrivate { + + +// #pragma mark - CatalogAddOnInfo + + +CatalogAddOnInfo::CatalogAddOnInfo(const BString& name, const BString& path, + uint8 priority) + : + fInstantiateFunc(NULL), + fCreateFunc(NULL), + fLanguagesFunc(NULL), + fName(name), + fPath(path), + fAddOnImage(B_NO_INIT), + fPriority(priority), + fIsEmbedded(path.Length()==0) +{ +} + + +CatalogAddOnInfo::~CatalogAddOnInfo() +{ + int32 count = fLoadedCatalogs.CountItems(); + for (int32 i = 0; i < count; ++i) { + BCatalogData* cat + = static_cast<BCatalogData*>(fLoadedCatalogs.ItemAt(i)); + delete cat; + } + fLoadedCatalogs.MakeEmpty(); + UnloadIfPossible(); +} + + +bool +CatalogAddOnInfo::MakeSureItsLoaded() +{ + if (!fIsEmbedded && fAddOnImage < B_OK) { + // add-on has not been loaded yet, so we try to load it: + BString fullAddOnPath(fPath); + fullAddOnPath << "/" << fName; + fAddOnImage = load_add_on(fullAddOnPath.String()); + if (fAddOnImage >= B_OK) { + get_image_symbol(fAddOnImage, "instantiate_catalog", + B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateFunc); + get_image_symbol(fAddOnImage, "create_catalog", + B_SYMBOL_TYPE_TEXT, (void**)&fCreateFunc); + get_image_symbol(fAddOnImage, "get_available_languages", + B_SYMBOL_TYPE_TEXT, (void**)&fLanguagesFunc); + } else + return false; + } else if (fIsEmbedded) { + // The built-in catalog still has to provide this function + fLanguagesFunc = default_catalog_get_available_languages; + } + return true; +} + + +void +CatalogAddOnInfo::UnloadIfPossible() +{ + if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) { + unload_add_on(fAddOnImage); + fAddOnImage = B_NO_INIT; + fInstantiateFunc = NULL; + fCreateFunc = NULL; + fLanguagesFunc = NULL; + } +} + + +// #pragma mark - LocaleRosterData + + +namespace { + + +static const char* kPriorityAttr = "ADDON:priority"; + +static const char* kLanguageField = "language"; +static const char* kTimezoneField = "timezone"; +static const char* kTranslateFilesystemField = "filesys"; + + +} // anonymous namespace + + +LocaleRosterData::LocaleRosterData(const BLanguage& language, + const BFormattingConventions& conventions) + : + fLock("LocaleRosterData"), + fDefaultLocale(&language, &conventions), + fIsFilesystemTranslationPreferred(false), + fAreResourcesLoaded(false) +{ + fInitStatus = _Initialize(); +} + + +LocaleRosterData::~LocaleRosterData() +{ + BAutolock lock(fLock); + + _CleanupCatalogAddOns(); +} + + +status_t +LocaleRosterData::InitCheck() const +{ + return fAreResourcesLoaded ? B_OK : B_NO_INIT; +} + + +status_t +LocaleRosterData::Refresh() +{ + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + _LoadLocaleSettings(); + _LoadTimeSettings(); + + return B_OK; +} + + +int +LocaleRosterData::CompareInfos(const void* left, const void* right) +{ + return ((CatalogAddOnInfo*)right)->fPriority + - ((CatalogAddOnInfo*)left)->fPriority; +} + + +status_t +LocaleRosterData::SetDefaultFormattingConventions( + const BFormattingConventions& newFormattingConventions) +{ + status_t status = B_OK; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + status = _SetDefaultFormattingConventions(newFormattingConventions); + + if (status == B_OK) + status = _SaveLocaleSettings(); + + if (status == B_OK) { + BMessage updateMessage(B_LOCALE_CHANGED); + status = _AddDefaultFormattingConventionsToMessage(&updateMessage); + if (status == B_OK) + status = be_roster->Broadcast(&updateMessage); + } + + return status; +} + + +status_t +LocaleRosterData::SetDefaultTimeZone(const BTimeZone& newZone) +{ + status_t status = B_OK; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + status = _SetDefaultTimeZone(newZone); + + if (status == B_OK) + status = _SaveTimeSettings(); + + if (status == B_OK) { + BMessage updateMessage(B_LOCALE_CHANGED); + status = _AddDefaultTimeZoneToMessage(&updateMessage); + if (status == B_OK) + status = be_roster->Broadcast(&updateMessage); + } + + return status; +} + + +status_t +LocaleRosterData::SetPreferredLanguages(const BMessage* languages) +{ + status_t status = B_OK; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + status = _SetPreferredLanguages(languages); + + if (status == B_OK) + status = _SaveLocaleSettings(); + + if (status == B_OK) { + BMessage updateMessage(B_LOCALE_CHANGED); + status = _AddPreferredLanguagesToMessage(&updateMessage); + if (status == B_OK) + status = be_roster->Broadcast(&updateMessage); + } + + return status; +} + + +status_t +LocaleRosterData::SetFilesystemTranslationPreferred(bool preferred) +{ + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + _SetFilesystemTranslationPreferred(preferred); + + status_t status = _SaveLocaleSettings(); + + if (status == B_OK) { + BMessage updateMessage(B_LOCALE_CHANGED); + status = _AddFilesystemTranslationPreferenceToMessage(&updateMessage); + if (status == B_OK) + status = be_roster->Broadcast(&updateMessage); + } + + return status; +} + + +status_t +LocaleRosterData::GetResources(BResources** resources) +{ + if (resources == NULL) + return B_BAD_VALUE; + + if (!fAreResourcesLoaded) { + status_t result + = fResources.SetToImage((const void*)&BLocaleRoster::Default); + if (result != B_OK) + return result; + + result = fResources.PreloadResourceType(); + if (result != B_OK) + return result; + + fAreResourcesLoaded = true; + } + + *resources = &fResources; + return B_OK; +} + + +status_t +LocaleRosterData::_Initialize() +{ + status_t result = _InitializeCatalogAddOns(); + if (result != B_OK) + return result; + + if ((result = Refresh()) != B_OK) + return result; + + fInitStatus = B_OK; + return B_OK; +} + + +/* +iterate over add-on-folders and collect information about each +catalog-add-ons (types of catalogs) into fCatalogAddOnInfos. +*/ +status_t +LocaleRosterData::_InitializeCatalogAddOns() +{ + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + // add info about embedded default catalog: + CatalogAddOnInfo* defaultCatalogAddOnInfo + = new(std::nothrow) CatalogAddOnInfo("Default", "", + DefaultCatalog::kDefaultCatalogAddOnPriority); + if (!defaultCatalogAddOnInfo) + return B_NO_MEMORY; + + defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate; + defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create; + fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo); + + directory_which folders[] = { + B_USER_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY, + }; + BPath addOnPath; + BDirectory addOnFolder; + char buf[4096]; + status_t err; + for (uint32 f = 0; f < sizeof(folders) / sizeof(directory_which); ++f) { + find_directory(folders[f], &addOnPath); + BString addOnFolderName(addOnPath.Path()); + addOnFolderName << "/locale/catalogs"; + + system_info info; + if (get_system_info(&info) == B_OK + && (info.abi & B_HAIKU_ABI_MAJOR) + != (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) { + switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) { + case B_HAIKU_ABI_GCC_2: + addOnFolderName << "/gcc2"; + break; + case B_HAIKU_ABI_GCC_4: + addOnFolderName << "/gcc4"; + break; + } + } + + + err = addOnFolder.SetTo(addOnFolderName.String()); + if (err != B_OK) + continue; + + // scan through all the folder's entries for catalog add-ons: + int32 count; + int8 priority; + entry_ref eref; + BNode node; + BEntry entry; + dirent* dent; + while ((count = addOnFolder.GetNextDirents((dirent*)buf, 4096)) > 0) { + dent = (dirent*)buf; + while (count-- > 0) { + if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") + && strcmp(dent->d_name, "gcc2") + && strcmp(dent->d_name, "gcc4")) { + // we have found (what should be) a catalog-add-on: + eref.device = dent->d_pdev; + eref.directory = dent->d_pino; + eref.set_name(dent->d_name); + entry.SetTo(&eref, true); + // traverse through any links to get to the real thang! + node.SetTo(&entry); + priority = -1; + if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0, + &priority, sizeof(int8)) <= 0) { + // add-on has no priority-attribute yet, so we load it + // to fetch the priority from the corresponding + // symbol... + BString fullAddOnPath(addOnFolderName); + fullAddOnPath << "/" << dent->d_name; + image_id image = load_add_on(fullAddOnPath.String()); + if (image >= B_OK) { + uint8* prioPtr; + if (get_image_symbol(image, "gCatalogAddOnPriority", + B_SYMBOL_TYPE_DATA, + (void**)&prioPtr) == B_OK) { + priority = *prioPtr; + node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0, + &priority, sizeof(int8)); + } + unload_add_on(image); + } + } + + if (priority >= 0) { + // add-ons with priority < 0 will be ignored + CatalogAddOnInfo* addOnInfo + = new(std::nothrow) CatalogAddOnInfo(dent->d_name, + addOnFolderName, priority); + if (addOnInfo) + fCatalogAddOnInfos.AddItem((void*)addOnInfo); + } + } + // Bump the dirent-pointer by length of the dirent just handled: + dent = (dirent*)((char*)dent + dent->d_reclen); + } + } + } + fCatalogAddOnInfos.SortItems(CompareInfos); + + return B_OK; +} + + +/* + * unloads all catalog-add-ons (which will throw away all loaded catalogs, too) + */ +void +LocaleRosterData::_CleanupCatalogAddOns() +{ + BAutolock lock(fLock); + if (!lock.IsLocked()) + return; + + int32 count = fCatalogAddOnInfos.CountItems(); + for (int32 i = 0; i<count; ++i) { + CatalogAddOnInfo* info + = static_cast<CatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i)); + delete info; + } + fCatalogAddOnInfos.MakeEmpty(); +} + + +status_t +LocaleRosterData::_LoadLocaleSettings() +{ + BPath path; + BFile file; + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status == B_OK) { + path.Append("Locale settings"); + status = file.SetTo(path.Path(), B_READ_ONLY); + } + BMessage settings; + if (status == B_OK) + status = settings.Unflatten(&file); + + if (status == B_OK) { + BFormattingConventions conventions(&settings); + fDefaultLocale.SetFormattingConventions(conventions); + + _SetPreferredLanguages(&settings); + + bool preferred; + if (settings.FindBool(kTranslateFilesystemField, &preferred) == B_OK) + _SetFilesystemTranslationPreferred(preferred); + + return B_OK; + } + + + // Something went wrong (no settings file or invalid BMessage), so we + // set everything to default values + + fPreferredLanguages.MakeEmpty(); + fPreferredLanguages.AddString(kLanguageField, "en"); + BLanguage defaultLanguage("en_US"); + fDefaultLocale.SetLanguage(defaultLanguage); + BFormattingConventions conventions("en_US"); + fDefaultLocale.SetFormattingConventions(conventions); + + return status; +} + + +status_t +LocaleRosterData::_LoadTimeSettings() +{ + BPath path; + BFile file; + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status == B_OK) { + path.Append("Time settings"); + status = file.SetTo(path.Path(), B_READ_ONLY); + } + BMessage settings; + if (status == B_OK) + status = settings.Unflatten(&file); + if (status == B_OK) { + BString timeZoneID; + if (settings.FindString(kTimezoneField, &timeZoneID) == B_OK) + _SetDefaultTimeZone(BTimeZone(timeZoneID.String())); + else + _SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone)); + + return B_OK; + } + + // Something went wrong (no settings file or invalid BMessage), so we + // set everything to default values + _SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone)); + + return status; +} + + +status_t +LocaleRosterData::_SaveLocaleSettings() +{ + BMessage settings; + status_t status = _AddDefaultFormattingConventionsToMessage(&settings); + if (status == B_OK) + _AddPreferredLanguagesToMessage(&settings); + if (status == B_OK) + _AddFilesystemTranslationPreferenceToMessage(&settings); + + BPath path; + if (status == B_OK) + status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + + BFile file; + if (status == B_OK) { + path.Append("Locale settings"); + status = file.SetTo(path.Path(), + B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); + } + if (status == B_OK) + status = settings.Flatten(&file); + if (status == B_OK) + status = file.Sync(); + + return status; +} + + +status_t +LocaleRosterData::_SaveTimeSettings() +{ + BMessage settings; + status_t status = _AddDefaultTimeZoneToMessage(&settings); + + BPath path; + if (status == B_OK) + status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + + BFile file; + if (status == B_OK) { + path.Append("Time settings"); + status = file.SetTo(path.Path(), + B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); + } + if (status == B_OK) + status = settings.Flatten(&file); + if (status == B_OK) + status = file.Sync(); + + return status; +} + + +status_t +LocaleRosterData::_SetDefaultFormattingConventions( + const BFormattingConventions& newFormattingConventions) +{ + fDefaultLocale.SetFormattingConventions(newFormattingConventions); + + UErrorCode icuError = U_ZERO_ERROR; + Locale icuLocale = Locale::createCanonical(newFormattingConventions.ID()); + if (icuLocale.isBogus()) + return B_ERROR; + + Locale::setDefault(icuLocale, icuError); + if (!U_SUCCESS(icuError)) + return B_ERROR; + + return B_OK; +} + + +status_t +LocaleRosterData::_SetDefaultTimeZone(const BTimeZone& newZone) +{ + fDefaultTimeZone = newZone; + + TimeZone* timeZone = TimeZone::createTimeZone(newZone.ID().String()); + if (timeZone == NULL) + return B_ERROR; + TimeZone::adoptDefault(timeZone); + + return B_OK; +} + + +status_t +LocaleRosterData::_SetPreferredLanguages(const BMessage* languages) +{ + BString langName; + if (languages != NULL + && languages->FindString(kLanguageField, &langName) == B_OK) { + fDefaultLocale.SetCollator(BCollator(langName.String())); + fDefaultLocale.SetLanguage(BLanguage(langName.String())); + + fPreferredLanguages.RemoveName(kLanguageField); + for (int i = 0; languages->FindString(kLanguageField, i, &langName) + == B_OK; i++) { + fPreferredLanguages.AddString(kLanguageField, langName); + } + } else { + fPreferredLanguages.MakeEmpty(); + fPreferredLanguages.AddString(kLanguageField, "en"); + fDefaultLocale.SetCollator(BCollator("en")); + } + + return B_OK; +} + + +void +LocaleRosterData::_SetFilesystemTranslationPreferred(bool preferred) +{ + fIsFilesystemTranslationPreferred = preferred; +} + + +status_t +LocaleRosterData::_AddDefaultFormattingConventionsToMessage( + BMessage* message) const +{ + BFormattingConventions conventions; + fDefaultLocale.GetFormattingConventions(&conventions); + + return conventions.Archive(message); +} + + +status_t +LocaleRosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const +{ + return message->AddString(kTimezoneField, fDefaultTimeZone.ID()); +} + + +status_t +LocaleRosterData::_AddPreferredLanguagesToMessage(BMessage* message) const +{ + status_t status = B_OK; + + BString langName; + for (int i = 0; fPreferredLanguages.FindString("language", i, + &langName) == B_OK; i++) { + status = message->AddString(kLanguageField, langName); + if (status != B_OK) + break; + } + + return status; +} + + +status_t +LocaleRosterData::_AddFilesystemTranslationPreferenceToMessage( + BMessage* message) const +{ + return message->AddBool(kTranslateFilesystemField, + fIsFilesystemTranslationPreferred); +} + + +} // namespace BPrivate diff --git a/src/kits/locale/MutableLocaleRoster.cpp b/src/kits/locale/MutableLocaleRoster.cpp index 6689dd2..3ca25e3 100644 --- a/src/kits/locale/MutableLocaleRoster.cpp +++ b/src/kits/locale/MutableLocaleRoster.cpp @@ -10,702 +10,41 @@ #include <MutableLocaleRoster.h> -#include <set> - #include <pthread.h> -#include <AppFileInfo.h> #include <Application.h> #include <Autolock.h> #include <Catalog.h> -#include <Collator.h> +#include <CatalogData.h> #include <Debug.h> -#include <DefaultCatalog.h> -#include <Directory.h> #include <Entry.h> -#include <File.h> -#include <FindDirectory.h> #include <FormattingConventions.h> #include <Language.h> -#include <Locale.h> -#include <Node.h> -#include <Path.h> -#include <Roster.h> +#include <LocaleRosterData.h> #include <String.h> -#include <TimeZone.h> - -#include <ICUWrapper.h> - -// ICU includes -#include <unicode/locid.h> -#include <unicode/timezone.h> namespace BPrivate { -// #pragma mark - CatalogAddOnInfo - - -CatalogAddOnInfo::CatalogAddOnInfo(const BString& name, const BString& path, - uint8 priority) - : - fInstantiateFunc(NULL), - fCreateFunc(NULL), - fLanguagesFunc(NULL), - fName(name), - fPath(path), - fAddOnImage(B_NO_INIT), - fPriority(priority), - fIsEmbedded(path.Length()==0) -{ -} - - -CatalogAddOnInfo::~CatalogAddOnInfo() -{ - int32 count = fLoadedCatalogs.CountItems(); - for (int32 i = 0; i < count; ++i) { - BCatalogData* cat - = static_cast<BCatalogData*>(fLoadedCatalogs.ItemAt(i)); - delete cat; - } - fLoadedCatalogs.MakeEmpty(); - UnloadIfPossible(); -} - - -bool -CatalogAddOnInfo::MakeSureItsLoaded() -{ - if (!fIsEmbedded && fAddOnImage < B_OK) { - // add-on has not been loaded yet, so we try to load it: - BString fullAddOnPath(fPath); - fullAddOnPath << "/" << fName; - fAddOnImage = load_add_on(fullAddOnPath.String()); - if (fAddOnImage >= B_OK) { - get_image_symbol(fAddOnImage, "instantiate_catalog", - B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateFunc); - get_image_symbol(fAddOnImage, "create_catalog", - B_SYMBOL_TYPE_TEXT, (void**)&fCreateFunc); - get_image_symbol(fAddOnImage, "get_available_languages", - B_SYMBOL_TYPE_TEXT, (void**)&fLanguagesFunc); - } else - return false; - } else if (fIsEmbedded) { - // The built-in catalog still has to provide this function - fLanguagesFunc = default_catalog_get_available_languages; - } - return true; -} - - -void -CatalogAddOnInfo::UnloadIfPossible() -{ - if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) { - unload_add_on(fAddOnImage); - fAddOnImage = B_NO_INIT; - fInstantiateFunc = NULL; - fCreateFunc = NULL; - fLanguagesFunc = NULL; - } -} - - -// #pragma mark - RosterData - - namespace { -static const char* kPriorityAttr = "ADDON:priority"; - -static const char* kLanguageField = "language"; -static const char* kTimezoneField = "timezone"; -static const char* kTranslateFilesystemField = "filesys"; - +static MutableLocaleRoster* sLocaleRoster; -static RosterData* sRosterData = NULL; -static pthread_once_t sRosterDataInitOnce = PTHREAD_ONCE_INIT; - - -static struct RosterDataReaper { - ~RosterDataReaper() - { - delete sRosterData; - sRosterData = NULL; - } -} sRosterDataReaper; +static pthread_once_t sLocaleRosterInitOnce = PTHREAD_ONCE_INIT; } // anonymous namespace - static void -InitializeRosterData() -{ - sRosterData = new (std::nothrow) RosterData(BLanguage("en_US"), - BFormattingConventions("en_US")); -} - - -RosterData::RosterData(const BLanguage& language, - const BFormattingConventions& conventions) - : - fLock("LocaleRosterData"), - fDefaultLocale(&language, &conventions), - fIsFilesystemTranslationPreferred(false), - fAreResourcesLoaded(false) -{ - fInitStatus = _Initialize(); -} - - -RosterData::~RosterData() -{ - BAutolock lock(fLock); - - _CleanupCatalogAddOns(); -} - - -/*static*/ RosterData* -RosterData::Default() -{ - if (sRosterData == NULL) - pthread_once(&sRosterDataInitOnce, &BPrivate::InitializeRosterData); - - return sRosterData; -} - - -status_t -RosterData::InitCheck() const -{ - return fAreResourcesLoaded ? B_OK : B_NO_INIT; -} - - -status_t -RosterData::Refresh() -{ - BAutolock lock(fLock); - if (!lock.IsLocked()) - return B_ERROR; - - _LoadLocaleSettings(); - _LoadTimeSettings(); - - return B_OK; -} - - -int -RosterData::CompareInfos(const void* left, const void* right) -{ - return ((CatalogAddOnInfo*)right)->fPriority - - ((CatalogAddOnInfo*)left)->fPriority; -} - - -status_t -RosterData::SetDefaultFormattingConventions( - const BFormattingConventions& newFormattingConventions) -{ - status_t status = B_OK; - - BAutolock lock(fLock); - if (!lock.IsLocked()) - return B_ERROR; - - status = _SetDefaultFormattingConventions(newFormattingConventions); - - if (status == B_OK) - status = _SaveLocaleSettings(); - - if (status == B_OK) { - BMessage updateMessage(B_LOCALE_CHANGED); - status = _AddDefaultFormattingConventionsToMessage(&updateMessage); - if (status == B_OK) - status = be_roster->Broadcast(&updateMessage); - } - - return status; -} - - -status_t -RosterData::SetDefaultTimeZone(const BTimeZone& newZone) -{ - status_t status = B_OK; - - BAutolock lock(fLock); - if (!lock.IsLocked()) - return B_ERROR; - - status = _SetDefaultTimeZone(newZone); - - if (status == B_OK) - status = _SaveTimeSettings(); - - if (status == B_OK) { - BMessage updateMessage(B_LOCALE_CHANGED); - status = _AddDefaultTimeZoneToMessage(&updateMessage); - if (status == B_OK) - status = be_roster->Broadcast(&updateMessage); - } - - return status; -} - - -status_t -RosterData::SetPreferredLanguages(const BMessage* languages) -{ - status_t status = B_OK; - - BAutolock lock(fLock); - if (!lock.IsLocked()) - return B_ERROR; - - status = _SetPreferredLanguages(languages); - - if (status == B_OK) - status = _SaveLocaleSettings(); - - if (status == B_OK) { - BMessage updateMessage(B_LOCALE_CHANGED); - status = _AddPreferredLanguagesToMessage(&updateMessage); - if (status == B_OK) - status = be_roster->Broadcast(&updateMessage); - } - - return status; -} - - -status_t -RosterData::SetFilesystemTranslationPreferred(bool preferred) -{ - BAutolock lock(fLock); - if (!lock.IsLocked()) - return B_ERROR; - - _SetFilesystemTranslationPreferred(preferred); - - status_t status = _SaveLocaleSettings(); - - if (status == B_OK) { - BMessage updateMessage(B_LOCALE_CHANGED); - status = _AddFilesystemTranslationPreferenceToMessage(&updateMessage); - if (status == B_OK) - status = be_roster->Broadcast(&updateMessage); - } - - return status; -} - - -status_t -RosterData::_Initialize() -{ - status_t result = _InitializeCatalogAddOns(); - if (result != B_OK) - return result; - - if ((result = Refresh()) != B_OK) - return result; - - fInitStatus = B_OK; - return B_OK; -} - - -/* -iterate over add-on-folders and collect information about each -catalog-add-ons (types of catalogs) into fCatalogAddOnInfos. -*/ -status_t -RosterData::_InitializeCatalogAddOns() +InitializeLocaleRoster() { - BAutolock lock(fLock); - if (!lock.IsLocked()) - return B_ERROR; - - // add info about embedded default catalog: - CatalogAddOnInfo* defaultCatalogAddOnInfo - = new(std::nothrow) CatalogAddOnInfo("Default", "", - DefaultCatalog::kDefaultCatalogAddOnPriority); - if (!defaultCatalogAddOnInfo) - return B_NO_MEMORY; - - defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate; - defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create; - fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo); - - directory_which folders[] = { - B_USER_ADDONS_DIRECTORY, - B_COMMON_ADDONS_DIRECTORY, - B_SYSTEM_ADDONS_DIRECTORY, - }; - BPath addOnPath; - BDirectory addOnFolder; - char buf[4096]; - status_t err; - for (uint32 f = 0; f < sizeof(folders) / sizeof(directory_which); ++f) { - find_directory(folders[f], &addOnPath); - BString addOnFolderName(addOnPath.Path()); - addOnFolderName << "/locale/catalogs"; - - system_info info; - if (get_system_info(&info) == B_OK - && (info.abi & B_HAIKU_ABI_MAJOR) - != (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) { - switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) { - case B_HAIKU_ABI_GCC_2: - addOnFolderName << "/gcc2"; - break; - case B_HAIKU_ABI_GCC_4: - addOnFolderName << "/gcc4"; - break; - } - } - - - err = addOnFolder.SetTo(addOnFolderName.String()); - if (err != B_OK) - continue; - - // scan through all the folder's entries for catalog add-ons: - int32 count; - int8 priority; - entry_ref eref; - BNode node; - BEntry entry; - dirent* dent; - while ((count = addOnFolder.GetNextDirents((dirent*)buf, 4096)) > 0) { - dent = (dirent*)buf; - while (count-- > 0) { - if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") - && strcmp(dent->d_name, "gcc2") - && strcmp(dent->d_name, "gcc4")) { - // we have found (what should be) a catalog-add-on: - eref.device = dent->d_pdev; - eref.directory = dent->d_pino; - eref.set_name(dent->d_name); - entry.SetTo(&eref, true); - // traverse through any links to get to the real thang! - node.SetTo(&entry); - priority = -1; - if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0, - &priority, sizeof(int8)) <= 0) { - // add-on has no priority-attribute yet, so we load it - // to fetch the priority from the corresponding - // symbol... - BString fullAddOnPath(addOnFolderName); - fullAddOnPath << "/" << dent->d_name; - image_id image = load_add_on(fullAddOnPath.String()); - if (image >= B_OK) { - uint8* prioPtr; - if (get_image_symbol(image, "gCatalogAddOnPriority", - B_SYMBOL_TYPE_DATA, - (void**)&prioPtr) == B_OK) { - priority = *prioPtr; - node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0, - &priority, sizeof(int8)); - } - unload_add_on(image); - } - } - - if (priority >= 0) { - // add-ons with priority < 0 will be ignored - CatalogAddOnInfo* addOnInfo - = new(std::nothrow) CatalogAddOnInfo(dent->d_name, - addOnFolderName, priority); - if (addOnInfo) - fCatalogAddOnInfos.AddItem((void*)addOnInfo); - } - } - // Bump the dirent-pointer by length of the dirent just handled: - dent = (dirent*)((char*)dent + dent->d_reclen); - } - } - } - fCatalogAddOnInfos.SortItems(CompareInfos); - - return B_OK; -} - - -/* - * unloads all catalog-add-ons (which will throw away all loaded catalogs, too) - */ -void -RosterData::_CleanupCatalogAddOns() -{ - BAutolock lock(fLock); - if (!lock.IsLocked()) - return; - - int32 count = fCatalogAddOnInfos.CountItems(); - for (int32 i = 0; i<count; ++i) { - CatalogAddOnInfo* info - = static_cast<CatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i)); - delete info; - } - fCatalogAddOnInfos.MakeEmpty(); -} - - -status_t -RosterData::_LoadLocaleSettings() -{ - BPath path; - BFile file; - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - if (status == B_OK) { - path.Append("Locale settings"); - status = file.SetTo(path.Path(), B_READ_ONLY); - } - BMessage settings; - if (status == B_OK) - status = settings.Unflatten(&file); - - if (status == B_OK) { - BFormattingConventions conventions(&settings); - fDefaultLocale.SetFormattingConventions(conventions); - - _SetPreferredLanguages(&settings); - - bool preferred; - if (settings.FindBool(kTranslateFilesystemField, &preferred) == B_OK) - _SetFilesystemTranslationPreferred(preferred); - - return B_OK; - } - - - // Something went wrong (no settings file or invalid BMessage), so we - // set everything to default values - - fPreferredLanguages.MakeEmpty(); - fPreferredLanguages.AddString(kLanguageField, "en"); - BLanguage defaultLanguage("en_US"); - fDefaultLocale.SetLanguage(defaultLanguage); - BFormattingConventions conventions("en_US"); - fDefaultLocale.SetFormattingConventions(conventions); - - return status; -} - - -status_t -RosterData::_LoadTimeSettings() -{ - BPath path; - BFile file; - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - if (status == B_OK) { - path.Append("Time settings"); - status = file.SetTo(path.Path(), B_READ_ONLY); - } - BMessage settings; - if (status == B_OK) - status = settings.Unflatten(&file); - if (status == B_OK) { - BString timeZoneID; - if (settings.FindString(kTimezoneField, &timeZoneID) == B_OK) - _SetDefaultTimeZone(BTimeZone(timeZoneID.String())); - else - _SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone)); - - return B_OK; - } - - // Something went wrong (no settings file or invalid BMessage), so we - // set everything to default values - _SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone)); - - return status; -} - - -status_t -RosterData::_SaveLocaleSettings() -{ - BMessage settings; - status_t status = _AddDefaultFormattingConventionsToMessage(&settings); - if (status == B_OK) - _AddPreferredLanguagesToMessage(&settings); - if (status == B_OK) - _AddFilesystemTranslationPreferenceToMessage(&settings); - - BPath path; - if (status == B_OK) - status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - - BFile file; - if (status == B_OK) { - path.Append("Locale settings"); - status = file.SetTo(path.Path(), - B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); - } - if (status == B_OK) - status = settings.Flatten(&file); - if (status == B_OK) - status = file.Sync(); - - return status; -} - - -status_t -RosterData::_SaveTimeSettings() -{ - BMessage settings; - status_t status = _AddDefaultTimeZoneToMessage(&settings); - - BPath path; - if (status == B_OK) - status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - - BFile file; - if (status == B_OK) { - path.Append("Time settings"); - status = file.SetTo(path.Path(), - B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); - } - if (status == B_OK) - status = settings.Flatten(&file); - if (status == B_OK) - status = file.Sync(); - - return status; -} - - -status_t -RosterData::_SetDefaultFormattingConventions( - const BFormattingConventions& newFormattingConventions) -{ - fDefaultLocale.SetFormattingConventions(newFormattingConventions); - - UErrorCode icuError = U_ZERO_ERROR; - Locale icuLocale = Locale::createCanonical(newFormattingConventions.ID()); - if (icuLocale.isBogus()) - return B_ERROR; - - Locale::setDefault(icuLocale, icuError); - if (!U_SUCCESS(icuError)) - return B_ERROR; - - return B_OK; -} - - -status_t -RosterData::_SetDefaultTimeZone(const BTimeZone& newZone) -{ - fDefaultTimeZone = newZone; - - TimeZone* timeZone = TimeZone::createTimeZone(newZone.ID().String()); - if (timeZone == NULL) - return B_ERROR; - TimeZone::adoptDefault(timeZone); - - return B_OK; + sLocaleRoster = new (std::nothrow) MutableLocaleRoster(); } -status_t -RosterData::_SetPreferredLanguages(const BMessage* languages) -{ - BString langName; - if (languages != NULL - && languages->FindString(kLanguageField, &langName) == B_OK) { - fDefaultLocale.SetCollator(BCollator(langName.String())); - fDefaultLocale.SetLanguage(BLanguage(langName.String())); - - fPreferredLanguages.RemoveName(kLanguageField); - for (int i = 0; languages->FindString(kLanguageField, i, &langName) - == B_OK; i++) { - fPreferredLanguages.AddString(kLanguageField, langName); - } - } else { - fPreferredLanguages.MakeEmpty(); - fPreferredLanguages.AddString(kLanguageField, "en"); - fDefaultLocale.SetCollator(BCollator("en")); - } - - return B_OK; -} - - -void -RosterData::_SetFilesystemTranslationPreferred(bool preferred) -{ - fIsFilesystemTranslationPreferred = preferred; -} - - -status_t -RosterData::_AddDefaultFormattingConventionsToMessage(BMessage* message) const -{ - BFormattingConventions conventions; - fDefaultLocale.GetFormattingConventions(&conventions); - - return conventions.Archive(message); -} - - -status_t -RosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const -{ - return message->AddString(kTimezoneField, fDefaultTimeZone.ID()); -} - - -status_t -RosterData::_AddPreferredLanguagesToMessage(BMessage* message) const -{ - status_t status = B_OK; - - BString langName; - for (int i = 0; fPreferredLanguages.FindString("language", i, - &langName) == B_OK; i++) { - status = message->AddString(kLanguageField, langName); - if (status != B_OK) - break; - } - - return status; -} - - -status_t -RosterData::_AddFilesystemTranslationPreferenceToMessage(BMessage* message) - const -{ - return message->AddBool(kTranslateFilesystemField, - fIsFilesystemTranslationPreferred); -} - - -// #pragma mark - MutableLocaleRoster - - -namespace { - - -static MutableLocaleRoster sLocaleRoster; - - -} // anonymous namespace - - MutableLocaleRoster::MutableLocaleRoster() { } @@ -719,7 +58,10 @@ MutableLocaleRoster::~MutableLocaleRoster() /*static*/ MutableLocaleRoster* MutableLocaleRoster::Default() { - return &sLocaleRoster; + if (sLocaleRoster == NULL) + pthread_once(&sLocaleRosterInitOnce, &InitializeLocaleRoster); + + return sLocaleRoster; } @@ -727,29 +69,28 @@ status_t MutableLocaleRoster::SetDefaultFormattingConventions( const BFormattingConventions& newFormattingConventions) { - return RosterData::Default()->SetDefaultFormattingConventions( - newFormattingConventions); + return fData->SetDefaultFormattingConventions(newFormattingConventions); } status_t MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone) { - return RosterData::Default()->SetDefaultTimeZone(newZone); + return fData->SetDefaultTimeZone(newZone); } status_t MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages) { - return RosterData::Default()->SetPreferredLanguages(languages); + return fData->SetPreferredLanguages(languages); } status_t MutableLocaleRoster::SetFilesystemTranslationPreferred(bool preferred) { - return RosterData::Default()->SetFilesystemTranslationPreferred(preferred); + return fData->SetFilesystemTranslationPreferred(preferred); } @@ -800,14 +141,14 @@ MutableLocaleRoster::CreateCatalog(const char* type, const char* signature, if (!type || !signature || !language) return NULL; - BAutolock lock(RosterData::Default()->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return NULL; - int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems(); + int32 count = fData->fCatalogAddOnInfos.CountItems(); for (int32 i = 0; i < count; ++i) { CatalogAddOnInfo* info = (CatalogAddOnInfo*) - RosterData::Default()->fCatalogAddOnInfos.ItemAt(i); + fData->fCatalogAddOnInfos.ItemAt(i); if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded() || !info->fCreateFunc) continue; @@ -838,14 +179,14 @@ BCatalogData* MutableLocaleRoster::LoadCatalog(const entry_ref& catalogOwner, const char* language, int32 fingerprint) const { - BAutolock lock(RosterData::Default()->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return NULL; - int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems(); + int32 count = fData->fCatalogAddOnInfos.CountItems(); for (int32 i = 0; i < count; ++i) { CatalogAddOnInfo* info = (CatalogAddOnInfo*) - RosterData::Default()->fCatalogAddOnInfos.ItemAt(i); + fData->fCatalogAddOnInfos.ItemAt(i); if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc) continue; @@ -909,7 +250,7 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog) if (!catalog) return B_BAD_VALUE; - BAutolock lock(RosterData::Default()->fLock); + BAutolock lock(fData->fLock); if (!lock.IsLocked()) return B_ERROR; @@ -918,10 +259,10 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog) while (catalog != NULL) { nextCatalog = catalog->Next(); - int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems(); + int32 count = fData->fCatalogAddOnInfos.CountItems(); for (int32 i = 0; i < count; ++i) { CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>( - RosterData::Default()->fCatalogAddOnInfos.ItemAt(i)); + fData->fCatalogAddOnInfos.ItemAt(i)); if (info->fLoadedCatalogs.HasItem(catalog)) { info->fLoadedCatalogs.RemoveItem(catalog); delete catalog;