summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPasi Matilainen <pasi.matilainen@digia.com>2012-03-02 13:06:08 (GMT)
committerQt by Nokia <qt-info@nokia.com>2012-03-07 23:40:08 (GMT)
commit41ba5997bba81e225dbc449bb60ac86d88ed7fe3 (patch)
treeb310e0f1d69b3cd8fd4f148848ef11d85cf892d9
parent0ef9762bbb176c842a90bc5aaad49a7f2b054ad6 (diff)
downloadQt-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.pro4
-rw-r--r--src/corelib/io/qsettings_mac.cpp82
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 {