[KDE/Mac] QSP patch/activator
René J.V. Bertin
rjvbertin at gmail.com
Sun Jan 31 15:28:57 UTC 2016
And here's the business part of the latest version of my QSP patch, by popular request (or not) :)
I've followed your (David's) remark that the actual QExtStandardPaths payload could be part of QStandardPaths; QExtStandardPaths is now purely header based - in qstandardpaths.h to be exact.
The idea is now that the user controls QSP at build time. When building with -DQT_USE_EXTSTANDARDPATHS QStandardPaths is replaced with QExtStandardPaths through a #define (except in the QSP implementation files of course). The member functions that take the *non-optional* mode argument are now part of QStandardPaths. I had to move the mode argument around a bit for the locate* versions in order to avoid ambiguity but that's not an issue at this point.
QExtStandardPaths overloads all relevant QSP functions through its standardLocations(), writableLocation(), locate() and locateAll() methods with a mode argument that has a default value (QSPDEFAULTXDGMODE) -- at least I hope that's indeed what it does.
An additional preprocessor token determines this default behaviour (= when code doesn't use the mode argument explicitly):
- QT_EXTSTANDARDPATHS_XDG_DEFAULT undefined or set to false: the patch has no effect; native QSP locations are returned regardless of the global mode switch (QSPDEFAULTXDGMODE is set to false).
- QT_EXTSTANDARDPATHS_XDG_DEFAULT=runtime : behaviour depends on the global mode switch; #define QSPDEFAULTXDGMODE isXDGLocationsEnabled()
- QT_EXTSTANDARDPATHS_XDG_DEFAULT=true : XDG-compliant locations are always returned, regardless of the global mode switch.
I could imagine replacing the xdg triplet with the alt, for instance, or something that refers to a legacy/traditional Unix approach. Does XDG actually stand for something (I presume the D is for desktop)?
I think it would be preferable to provide built-in values for the additional/alternative locations, but the mechanism would arguably more flexible (and thus have a higher value) if those defaults can be controlled via, for instance, qt.conf .
Cheers,
R.
-------------- next part --------------
diff --git a/qtbase/src/corelib/io/qstandardpaths.cpp b/qtbase/src/corelib/io/qstandardpaths.cpp
index 74252d1..128d10e 100644
--- a/qtbase/src/corelib/io/qstandardpaths.cpp
+++ b/qtbase/src/corelib/io/qstandardpaths.cpp
@@ -31,8 +31,10 @@
**
****************************************************************************/
+#undef QT_USE_EXTSTANDARDPATHS
#include "qstandardpaths.h"
+#include <qglobal.h>
#include <qdir.h>
#include <qfileinfo.h>
#include <qhash.h>
@@ -400,6 +402,85 @@ static bool existsAsSpecified(const QString &path, QStandardPaths::LocateOptions
return QFileInfo(path).isFile();
}
+#if defined(Q_OS_OSX)
+//#include <QDebug>
+/*!
+ This function enables or disables XDG locations on platforms where Qt can be configured
+ to use this kind of locations instead of locations following OS guidelines.
+ Currently this concerns only Mac OS X //and Cygwin?//
+ */
+void QStandardPaths::setXDGLocationsEnabled(bool xdgMode)
+{
+ usingXDGLocations = xdgMode;
+ isSetXDGLocations = true;
+ //qDebug() << Q_FUNC_INFO << "Setting usingXDGLocations=" << xdgMode;
+}
+
+/*!
+ This function returns true when XDG locations are used, unless QT_STANDARDPATHS_CANNOT_SWITCH
+ is set, in which case switching is disabled and the function always returns false.
+ */
+bool QStandardPaths::isXDGLocationsEnabled()
+{
+ if (qEnvironmentVariableIsSet("QT_STANDARDPATHS_CANNOT_SWITCH"))
+ return false;
+ else
+ return usingXDGLocations;
+}
+
+QString QStandardPaths::locate(StandardLocation type, bool xdgMode, const QString &fileName, LocateOptions options)
+{
+ const QStringList &dirs = standardLocations(type, xdgMode);
+ for (QStringList::const_iterator dir = dirs.constBegin(); dir != dirs.constEnd(); ++dir) {
+ const QString path = *dir + QLatin1Char('/') + fileName;
+ if (existsAsSpecified(path, options))
+ return path;
+ }
+ return QString();
+}
+
+QStringList QStandardPaths::locateAll(StandardLocation type, bool xdgMode, const QString &fileName, LocateOptions options)
+{
+ const QStringList &dirs = standardLocations(type, xdgMode);
+ QStringList result;
+ for (QStringList::const_iterator dir = dirs.constBegin(); dir != dirs.constEnd(); ++dir) {
+ const QString path = *dir + QLatin1Char('/') + fileName;
+ if (existsAsSpecified(path, options))
+ result.append(path);
+ }
+ //qDebug() << Q_FUNC_INFO << "search list=" << dirs;
+ return result;
+}
+
+/*!
+ Tries to find a file or directory called \a fileName in the standard locations
+ for \a type.
+
+ The full path to the first file or directory (depending on \a options) found is returned.
+ If no such file or directory can be found, an empty string is returned.
+ */
+QString QStandardPaths::locate(StandardLocation type, const QString &fileName, LocateOptions options)
+{
+ return QStandardPaths::locate(type, isXDGLocationsEnabled(), fileName, options);
+}
+
+/*!
+ Tries to find all files or directories called \a fileName in the standard locations
+ for \a type.
+
+ The \a options flag allows to specify whether to look for files or directories.
+
+ Returns the list of all the files that were found.
+ */
+QStringList QStandardPaths::locateAll(StandardLocation type, const QString &fileName, LocateOptions options)
+{
+ QStringList ret = QStandardPaths::locateAll(type, isXDGLocationsEnabled(), fileName, options);
+ //qDebug() << Q_FUNC_INFO << "type=" << type << "name=" << fileName << "found" << ret;
+ return ret;
+}
+
+#else // !Q_OS_OSX
+
/*!
Tries to find a file or directory called \a fileName in the standard locations
for \a type.
@@ -437,6 +518,7 @@ QStringList QStandardPaths::locateAll(StandardLocation type, const QString &file
}
return result;
}
+#endif // Q_OS_OSX
#ifdef Q_OS_WIN
static QStringList executableExtensions()
diff --git a/qtbase/src/corelib/io/qstandardpaths.h b/qtbase/src/corelib/io/qstandardpaths.h
index 5c0e08b..921d0c5 100644
--- a/qtbase/src/corelib/io/qstandardpaths.h
+++ b/qtbase/src/corelib/io/qstandardpaths.h
@@ -41,6 +41,8 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_STANDARDPATHS
+class Q_CORE_EXPORT QStandardPathsConfiguration;
+
class Q_CORE_EXPORT QStandardPaths
{
public:
@@ -68,6 +70,10 @@ public:
AppLocalDataLocation = DataLocation
};
+#if defined(Q_OS_OSX)
+ static bool isXDGLocationsEnabled();
+#endif // Q_OS_OSX
+
static QString writableLocation(StandardLocation type);
static QStringList standardLocations(StandardLocation type);
@@ -91,14 +97,93 @@ public:
static void setTestModeEnabled(bool testMode);
static bool isTestModeEnabled();
+#if defined(Q_OS_OSX)
+protected:
+ static void setXDGLocationsEnabled(bool xdgMode);
+
+ static QString writableLocation(StandardLocation type, bool xdgMode);
+ static QStringList standardLocations(StandardLocation type, bool xdgMode);
+
+ static QString locate(StandardLocation type, bool xdgMode, const QString &fileName, LocateOptions options = LocateFile);
+ static QStringList locateAll(StandardLocation type, bool xdgMode, const QString &fileName, LocateOptions options = LocateFile);
+#endif // Q_OS_OSX
+
private:
// prevent construction
QStandardPaths();
~QStandardPaths();
+#if defined(Q_OS_OSX)
+ static bool usingXDGLocations, isSetXDGLocations;
+
+ friend class QStandardPathsConfiguration;
+ friend class QExtStandardPaths;
+#endif // Q_OS_OSX
+};
+
+/* **** Extended QStandardPaths **** */
+
+#ifdef QT_EXTSTANDARDPATHS_XDG_DEFAULT
+#if QT_EXTSTANDARDPATHS_XDG_DEFAULT == runtime
+#define QSPDEFAULTXDGMODE isXDGLocationsEnabled()
+#else
+#define QSPDEFAULTXDGMODE true
+#endif // "runtime"
+#else
+#define QSPDEFAULTXDGMODE false
+#endif
+
+/*!
+ \class QExtStandardPaths
+ \inmodule QtCore
+ \brief The QExtStandardPaths class provides configurable methods for accessing standard paths.
+
+ This class inherits and elaborates on \class QStandardPaths, providing access to the support for
+ native vs. XDG-compliant standard locations that QStandardPaths has on certain platforms (currently
+ only Mac OS X).
+ When the QT_USE_EXTSTANDARDPATHS macro is defined, this class will replace QStandardPaths, and
+ in that case the QT_EXTSTANDARDPATHS_XDG_DEFAULT macro will define the behaviour of code that does
+ not use QExtStandardPaths explicitly itself. When undefined or QT_EXTSTANDARDPATHS_XDG_DEFAULT=false,
+ QExtStandardPaths will use native locations, even if QStandardPaths::isXDGLocationsEnabled() returns true.
+ When QT_EXTSTANDARDPATHS_XDG_DEFAULT=runtime, behaviour is controlled at runtime through
+ QStandardPaths::setXDGLocationsEnabled() and QStandardPaths::isXDGLocationsEnabled().
+ In all other cases QStandardPaths will use XDG-compliant locations.
+*/
+class Q_CORE_EXPORT QExtStandardPaths : public QStandardPaths
+{
+public:
+#if defined(Q_OS_OSX)
+ static QString writableLocation(StandardLocation type, bool xdgMode=QSPDEFAULTXDGMODE)
+ {
+ return QStandardPaths::writableLocation(type, xdgMode);
+ }
+ static QStringList standardLocations(StandardLocation type, bool xdgMode=QSPDEFAULTXDGMODE)
+ {
+ return QStandardPaths::standardLocations(type, xdgMode);
+ }
+
+ static QString locate(StandardLocation type, const QString &fileName, LocateOptions options = LocateFile, bool xdgMode=QSPDEFAULTXDGMODE)
+ {
+ return QStandardPaths::locate(type, xdgMode, fileName, options);
+ }
+ static QStringList locateAll(StandardLocation type, const QString &fileName, LocateOptions options = LocateFile, bool xdgMode=QSPDEFAULTXDGMODE)
+ {
+ return QStandardPaths::locateAll(type, xdgMode, fileName, options);
+ }
+#endif
+
+private:
+ // prevent construction
+ QExtStandardPaths();
+ ~QExtStandardPaths();
};
#endif // QT_NO_STANDARDPATHS
QT_END_NAMESPACE
+#ifdef QT_USE_EXTSTANDARDPATHS
+#define QStandardPaths QExtStandardPaths
+#endif // QT_USE_EXTSTANDARDPATHS
+
+
#endif // QSTANDARDPATHS_H
diff --git a/qtbase/src/corelib/io/qstandardpaths_mac.mm b/qtbase/src/corelib/io/qstandardpaths_mac.mm
index d6126ce..887c964 100644
--- a/qtbase/src/corelib/io/qstandardpaths_mac.mm
+++ b/qtbase/src/corelib/io/qstandardpaths_mac.mm
@@ -31,13 +31,16 @@
**
****************************************************************************/
+#undef QT_USE_EXTSTANDARDPATHS
#include "qstandardpaths.h"
#include <qdir.h>
#include <qurl.h>
#include <private/qcore_mac_p.h>
+#include <private/qfilesystemengine_p.h>
#ifndef QT_BOOTSTRAPPED
#include <qcoreapplication.h>
+#include <qlibraryinfo.h>
#endif
#include <CoreFoundation/CoreFoundation.h>
@@ -136,8 +139,155 @@ static QString macLocation(QStandardPaths::StandardLocation type, short domain)
return path;
}
-QString QStandardPaths::writableLocation(StandardLocation type)
+bool QStandardPaths::usingXDGLocations = false;
+bool QStandardPaths::isSetXDGLocations = false;
+
+static void normaliseDirs(QStringList &dirs)
+{
+ // Normalise paths, skip relative paths
+ QMutableListIterator<QString> it(dirs);
+ while (it.hasNext()) {
+ const QString dir = it.next();
+ if (!dir.startsWith(QLatin1Char('/')))
+ it.remove();
+ else
+ it.setValue(QDir::cleanPath(dir));
+ }
+
+ // Remove duplicates from the list, there's no use for duplicated
+ // paths in XDG_CONFIG_DIRS - if it's not found in the given
+ // directory the first time, it won't be there the second time.
+ // Plus duplicate paths causes problems for example for mimetypes,
+ // where duplicate paths here lead to duplicated mime types returned
+ // for a file, eg "text/plain,text/plain" instead of "text/plain"
+ dirs.removeDuplicates();
+}
+
+static QStringList xdgCacheDirs()
{
+ QStringList dirs;
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ QString xdgConfigDirsEnv = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
+ if (xdgConfigDirsEnv.isEmpty()) {
+#ifndef QT_BOOTSTRAPPED
+ dirs.append(QDir::homePath() + QString::fromLatin1("/.cache"));
+#endif
+ } else {
+ dirs = xdgConfigDirsEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
+
+ normaliseDirs(dirs);
+ }
+ return dirs;
+}
+
+static QStringList xdgConfigDirs()
+{
+ QStringList dirs;
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ QString xdgConfigDirsEnv = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
+ if (xdgConfigDirsEnv.isEmpty()) {
+#ifndef QT_BOOTSTRAPPED
+ dirs.append(QLibraryInfo::location(QLibraryInfo::PrefixPath) + QString::fromLatin1("/etc/xdg"));
+#endif
+ } else {
+ dirs = xdgConfigDirsEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
+
+ normaliseDirs(dirs);
+ }
+ return dirs;
+}
+
+static QStringList xdgDataDirs()
+{
+ QStringList dirs;
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ QString xdgDataDirsEnv = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
+ if (xdgDataDirsEnv.isEmpty()) {
+#ifndef QT_BOOTSTRAPPED
+ dirs.append(QLibraryInfo::location(QLibraryInfo::PrefixPath) + QString::fromLatin1("/share"));
+#endif
+ } else {
+ dirs = xdgDataDirsEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
+
+ normaliseDirs(dirs);
+ }
+ return dirs;
+}
+
+static QString xdgRuntimeDir()
+{
+ const uid_t myUid = geteuid();
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ QString xdgRTDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
+ if (xdgRTDir.isEmpty()) {
+ const QString userName = QFileSystemEngine::resolveUserName(myUid);
+// xdgRTDir = QDir::tempPath() + QLatin1String("/runtime-") + userName;
+ // NSTemporaryDirectory() returns the default $TMPDIR value, regardless of its current setting,
+ // which is more in line with XDG_RUNTIME_DIR requirements.
+ xdgRTDir = QString::fromNSString(NSTemporaryDirectory()) + QLatin1String("runtime-") + userName;
+ QDir dir(xdgRTDir);
+ if (!dir.exists()) {
+ if (!QDir().mkdir(xdgRTDir)) {
+ qWarning("QStandardPaths: error creating runtime directory %s: %s",
+ qPrintable(xdgRTDir), qPrintable(qt_error_string(errno)));
+ return QString();
+ }
+ }
+ } else {
+ qWarning("QStandardPaths: XDG_RUNTIME_DIR is set, using '%s'", qPrintable(xdgRTDir));
+ }
+ // "The directory MUST be owned by the user"
+ QFileInfo fileInfo(xdgRTDir);
+ if (fileInfo.ownerId() != myUid) {
+ qWarning("QStandardPaths: wrong ownership on runtime directory %s, %d instead of %d", qPrintable(xdgRTDir),
+ fileInfo.ownerId(), myUid);
+ return QString();
+ }
+ // "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
+ // since the current user is the owner, set both xxxUser and xxxOwner
+ QFile file(xdgRTDir);
+ const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
+ | QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
+ if (file.permissions() != wantedPerms && !file.setPermissions(wantedPerms)) {
+ qWarning("QStandardPaths: could not set correct permissions on runtime directory %s: %s",
+ qPrintable(xdgRTDir), qPrintable(file.errorString()));
+ return QString();
+ }
+ return xdgRTDir;
+}
+
+QString QStandardPaths::writableLocation(StandardLocation type, bool xdgMode)
+{
+ if (xdgMode) {
+ const QString prefix = (isTestModeEnabled())? QDir::homePath() + QLatin1String("/.qttest") : QDir::homePath();
+ QString path;
+ switch (type) {
+ case GenericDataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
+ path = prefix + QLatin1String("/.local/share");
+ if (type != GenericDataLocation)
+ appendOrganizationAndApp(path);
+ return path;
+ case GenericCacheLocation:
+ case CacheLocation:
+ path = prefix + QLatin1String("/.cache");
+ if (type == CacheLocation)
+ appendOrganizationAndApp(path);
+ return path;
+ case GenericConfigLocation:
+ case ConfigLocation:
+ return prefix + QLatin1String("/.config");
+ case ApplicationsLocation:
+ path = writableLocation(GenericDataLocation, xdgMode) + QLatin1String("/applications");
+ return path;
+ case RuntimeLocation:
+ return xdgRuntimeDir();
+ default:
+ break;
+ }
+ }
+
if (isTestModeEnabled()) {
const QString qttestDir = QDir::homePath() + QLatin1String("/.qttest");
QString path;
@@ -162,6 +312,9 @@ QString QStandardPaths::writableLocation(StandardLocation type)
if (type == AppConfigLocation)
appendOrganizationAndApp(path);
return path;
+ case ApplicationsLocation:
+ path = qttestDir + QLatin1String("/Applications");
+ return path;
default:
break;
}
@@ -178,16 +331,45 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case GenericCacheLocation:
case CacheLocation:
case RuntimeLocation:
+ case FontsLocation:
+ // the font location that is writable for all users is ~/Library/Fonts
return macLocation(type, kUserDomain);
default:
return macLocation(type, kOnAppropriateDisk);
}
}
-QStringList QStandardPaths::standardLocations(StandardLocation type)
+QString QStandardPaths::writableLocation(StandardLocation type)
+{
+ return QStandardPaths::writableLocation(type, isXDGLocationsEnabled());
+}
+
+QStringList QStandardPaths::standardLocations(StandardLocation type, bool xdgMode)
{
QStringList dirs;
+ if (xdgMode) {
+ switch (type) {
+ case GenericDataLocation:
+ dirs.append(xdgDataDirs());
+ break;
+ case GenericConfigLocation:
+ case ConfigLocation:
+ dirs.append(xdgConfigDirs());
+ break;
+ case GenericCacheLocation:
+ case CacheLocation:
+ dirs.append(xdgCacheDirs());
+ break;
+ case ApplicationsLocation:
+ QStringList xdgDirs = xdgDataDirs();
+ for (int i = 0; i < xdgDirs.count(); ++i)
+ xdgDirs[i].append(QLatin1String("/applications"));
+ dirs.append(xdgDirs);
+ break;
+ }
+ }
+
if (type == GenericDataLocation || type == AppDataLocation || type == AppLocalDataLocation || type == GenericCacheLocation || type == CacheLocation) {
const QString path = macLocation(type, kOnAppropriateDisk);
if (!path.isEmpty())
@@ -195,6 +377,14 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
}
if (type == AppDataLocation || type == AppLocalDataLocation) {
+ if (xdgMode) {
+ QStringList xdgDirs = xdgDataDirs();
+ for (int i = 0; i < xdgDirs.count(); ++i) {
+ appendOrganizationAndApp(xdgDirs[i]);
+ }
+ dirs.append(xdgDirs);
+ }
+
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle) {
CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle);
@@ -218,11 +408,22 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
dirs.append(bundlePath + resourcesPath);
}
}
- const QString localDir = writableLocation(type);
+ if (type == FontsLocation) {
+ // /Library/Fonts
+ dirs.append(macLocation(type,kLocalDomain));
+ // /System/Library/Fonts
+ dirs.append(macLocation(type,kSystemDomain));
+ }
+ const QString localDir = writableLocation(type, xdgMode);
dirs.prepend(localDir);
return dirs;
}
+QStringList QStandardPaths::standardLocations(StandardLocation type)
+{
+ return QStandardPaths::standardLocations(type, isXDGLocationsEnabled());
+}
+
#ifndef QT_BOOTSTRAPPED
QString QStandardPaths::displayName(StandardLocation type)
{
More information about the kde-mac
mailing list