diff options
author | Pasi Matilainen <pasi.matilainen@digia.com> | 2012-03-02 13:06:08 (GMT) |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-03-07 23:40:08 (GMT) |
commit | 41ba5997bba81e225dbc449bb60ac86d88ed7fe3 (patch) | |
tree | b310e0f1d69b3cd8fd4f148848ef11d85cf892d9 | |
parent | 0ef9762bbb176c842a90bc5aaad49a7f2b054ad6 (diff) | |
download | Qt-41ba5997bba81e225dbc449bb60ac86d88ed7fe3.zip Qt-41ba5997bba81e225dbc449bb60ac86d88ed7fe3.tar.gz Qt-41ba5997bba81e225dbc449bb60ac86d88ed7fe3.tar.bz2 |
Enable storage of global Qt settings in app-local settings file on Mac
The Mac App Store has limitations on where applications can write their
settings, and com.trolltech.plist is not allowed. Changed the settings
code to store all settings in the app-local file when the application
runs in sandbox, or when the application's Info.plist contains a key
"ForAppStore" with value "yes". The application's bundle identifier is
also used for naming the settings file in these cases.
Task-number: QTBUG-16549
Change-Id: Idd2241fbd7eb346da987226f05460642b0d6e5a3
Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
-rw-r--r-- | src/corelib/corelib.pro | 4 | ||||
-rw-r--r-- | src/corelib/io/qsettings_mac.cpp | 82 |
2 files changed, 84 insertions, 2 deletions
diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index 9673861..d7306e0 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -22,10 +22,10 @@ include(xml/xml.pri) !qpa:mac|darwin:LIBS_PRIVATE += -framework ApplicationServices qpa { contains(QT_CONFIG, coreservices) { - LIBS_PRIVATE += -framework CoreServices + LIBS_PRIVATE += -framework CoreServices -framework Security } } else:mac|darwin { - LIBS_PRIVATE += -framework CoreFoundation + LIBS_PRIVATE += -framework CoreFoundation -framework Security } mac:lib_bundle:DEFINES += QT_NO_DEBUG_PLUGIN_CHECK win32:DEFINES-=QT_NO_CAST_TO_ASCII diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp index 6d0af2a..3e3189e 100644 --- a/src/corelib/io/qsettings_mac.cpp +++ b/src/corelib/io/qsettings_mac.cpp @@ -45,6 +45,13 @@ #include "qdir.h" #include "qvarlengtharray.h" #include "private/qcore_mac_p.h" +#ifndef QT_BOOTSTRAPPED +#include "qcoreapplication.h" +#endif +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 +#include <Security/SecCode.h> +#include <Security/SecRequirement.h> +#endif QT_BEGIN_NAMESPACE @@ -343,6 +350,7 @@ class QMacSettingsPrivate : public QSettingsPrivate public: QMacSettingsPrivate(QSettings::Scope scope, const QString &organization, const QString &application); + QMacSettingsPrivate(CFStringRef bundleIdentifier); ~QMacSettingsPrivate(); void remove(const QString &key); @@ -423,6 +431,22 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString & sync(); } +QMacSettingsPrivate::QMacSettingsPrivate(CFStringRef bundleIdentifier) + : QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, QString(), QString()) +{ + // applicationId and suiteId are QCFStrings and take ownership, retain to prevent double deletes. + CFRetain(bundleIdentifier); + applicationId = bundleIdentifier; + CFRetain(bundleIdentifier); + suiteId = bundleIdentifier; + + numDomains = 1; + domains[0].userName = kCFPreferencesCurrentUser; + domains[0].applicationOrSuiteId = bundleIdentifier; + hostName = kCFPreferencesAnyHost; + sync(); +} + QMacSettingsPrivate::~QMacSettingsPrivate() { } @@ -579,6 +603,64 @@ QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, const QString &organization, const QString &application) { +#ifndef QT_BOOTSTRAPPED + static bool useAppLocalStorage = false; + static bool initialized = false; + + if (!initialized) { + bool inSandbox = false; + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + // If we are running on at least 10.7.0 and have the com.apple.security.app-sandbox + // entitlement, we are in a sandbox + SInt32 version = 0; + Gestalt(gestaltSystemVersion, &version); + SecCodeRef secCodeSelf; + if (version >= 0x1070 && SecCodeCopySelf(kSecCSDefaultFlags, &secCodeSelf) == errSecSuccess) { + SecRequirementRef sandboxReq; + CFStringRef entitlement = CFSTR("entitlement [\"com.apple.security.app-sandbox\"]"); + if (SecRequirementCreateWithString(entitlement, kSecCSDefaultFlags, &sandboxReq) == errSecSuccess) { + if (SecCodeCheckValidity(secCodeSelf, kSecCSDefaultFlags, sandboxReq) == errSecSuccess) + inSandbox = true; + CFRelease(sandboxReq); + } + CFRelease(secCodeSelf); + } +#endif + + bool forAppStore = false; + if (!inSandbox) { + CFTypeRef val = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("ForAppStore")); + forAppStore = (val && + CFGetTypeID(val) == CFStringGetTypeID() && + CFStringCompare(CFStringRef(val), CFSTR("yes"), kCFCompareCaseInsensitive) == 0); + } + + useAppLocalStorage = inSandbox || forAppStore; + initialized = true; + } + + if (useAppLocalStorage) { + // Ensure that the global and app-local settings go to the same file, since that's + // what we really want + if (organization == QLatin1String("Trolltech") || + organization.isEmpty() || + (organization == qApp->organizationDomain() && application == qApp->applicationName()) || + (organization == qApp->organizationName()) && application == qApp->applicationName()) + { + CFStringRef bundleIdentifier = CFBundleGetIdentifier(CFBundleGetMainBundle()); + if (!bundleIdentifier) { + qWarning("QSettingsPrivate::create: You must set the bundle identifier when using ForAppStore"); + } else { + QSettingsPrivate* settings = new QMacSettingsPrivate(bundleIdentifier); + if (organization == QLatin1String("Trolltech")) + settings->beginGroupOrArray(QSettingsGroup("QtLibrarySettings")); + return settings; + } + } + } +#endif + if (format == QSettings::NativeFormat) { return new QMacSettingsPrivate(scope, organization, application); } else { |