| 1 | /**************************************************************************** | 
|---|
| 2 | ** | 
|---|
| 3 | ** Copyright (C) 2020 The Qt Company Ltd. | 
|---|
| 4 | ** Copyright (C) 2020 Intel Corporation. | 
|---|
| 5 | ** Contact: https://www.qt.io/licensing/ | 
|---|
| 6 | ** | 
|---|
| 7 | ** This file is part of the QtCore module of the Qt Toolkit. | 
|---|
| 8 | ** | 
|---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$ | 
|---|
| 10 | ** Commercial License Usage | 
|---|
| 11 | ** Licensees holding valid commercial Qt licenses may use this file in | 
|---|
| 12 | ** accordance with the commercial license agreement provided with the | 
|---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in | 
|---|
| 14 | ** a written agreement between you and The Qt Company. For licensing terms | 
|---|
| 15 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
|---|
| 16 | ** information use the contact form at https://www.qt.io/contact-us. | 
|---|
| 17 | ** | 
|---|
| 18 | ** GNU Lesser General Public License Usage | 
|---|
| 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
|---|
| 20 | ** General Public License version 3 as published by the Free Software | 
|---|
| 21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
|---|
| 22 | ** packaging of this file. Please review the following information to | 
|---|
| 23 | ** ensure the GNU Lesser General Public License version 3 requirements | 
|---|
| 24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
|---|
| 25 | ** | 
|---|
| 26 | ** GNU General Public License Usage | 
|---|
| 27 | ** Alternatively, this file may be used under the terms of the GNU | 
|---|
| 28 | ** General Public License version 2.0 or (at your option) the GNU General | 
|---|
| 29 | ** Public license version 3 or any later version approved by the KDE Free | 
|---|
| 30 | ** Qt Foundation. The licenses are as published by the Free Software | 
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
|---|
| 32 | ** included in the packaging of this file. Please review the following | 
|---|
| 33 | ** information to ensure the GNU General Public License requirements will | 
|---|
| 34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
|---|
| 35 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
|---|
| 36 | ** | 
|---|
| 37 | ** $QT_END_LICENSE$ | 
|---|
| 38 | ** | 
|---|
| 39 | ****************************************************************************/ | 
|---|
| 40 |  | 
|---|
| 41 | #include "qstandardpaths.h" | 
|---|
| 42 | #include <qdir.h> | 
|---|
| 43 | #include <qfile.h> | 
|---|
| 44 | #include <qhash.h> | 
|---|
| 45 | #include <qtextstream.h> | 
|---|
| 46 | #if QT_CONFIG(regularexpression) | 
|---|
| 47 | #include <qregularexpression.h> | 
|---|
| 48 | #endif | 
|---|
| 49 | #include <private/qfilesystemengine_p.h> | 
|---|
| 50 | #include <errno.h> | 
|---|
| 51 | #include <stdlib.h> | 
|---|
| 52 |  | 
|---|
| 53 | #ifndef QT_BOOTSTRAPPED | 
|---|
| 54 | #include <qcoreapplication.h> | 
|---|
| 55 | #endif | 
|---|
| 56 |  | 
|---|
| 57 | #ifndef QT_NO_STANDARDPATHS | 
|---|
| 58 |  | 
|---|
| 59 | QT_BEGIN_NAMESPACE | 
|---|
| 60 |  | 
|---|
| 61 | static void appendOrganizationAndApp(QString &path) | 
|---|
| 62 | { | 
|---|
| 63 | #ifndef QT_BOOTSTRAPPED | 
|---|
| 64 | const QString org = QCoreApplication::organizationName(); | 
|---|
| 65 | if (!org.isEmpty()) | 
|---|
| 66 | path += QLatin1Char('/') + org; | 
|---|
| 67 | const QString appName = QCoreApplication::applicationName(); | 
|---|
| 68 | if (!appName.isEmpty()) | 
|---|
| 69 | path += QLatin1Char('/') + appName; | 
|---|
| 70 | #else | 
|---|
| 71 | Q_UNUSED(path); | 
|---|
| 72 | #endif | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | #if QT_CONFIG(regularexpression) | 
|---|
| 76 | static QLatin1String xdg_key_name(QStandardPaths::StandardLocation type) | 
|---|
| 77 | { | 
|---|
| 78 | switch (type) { | 
|---|
| 79 | case QStandardPaths::DesktopLocation: | 
|---|
| 80 | return QLatin1String( "DESKTOP"); | 
|---|
| 81 | case QStandardPaths::DocumentsLocation: | 
|---|
| 82 | return QLatin1String( "DOCUMENTS"); | 
|---|
| 83 | case QStandardPaths::PicturesLocation: | 
|---|
| 84 | return QLatin1String( "PICTURES"); | 
|---|
| 85 | case QStandardPaths::MusicLocation: | 
|---|
| 86 | return QLatin1String( "MUSIC"); | 
|---|
| 87 | case QStandardPaths::MoviesLocation: | 
|---|
| 88 | return QLatin1String( "VIDEOS"); | 
|---|
| 89 | case QStandardPaths::DownloadLocation: | 
|---|
| 90 | return QLatin1String( "DOWNLOAD"); | 
|---|
| 91 | default: | 
|---|
| 92 | return QLatin1String(); | 
|---|
| 93 | } | 
|---|
| 94 | } | 
|---|
| 95 | #endif | 
|---|
| 96 |  | 
|---|
| 97 | static bool checkXdgRuntimeDir(const QString &xdgRuntimeDir) | 
|---|
| 98 | { | 
|---|
| 99 | auto describeMetaData = [](const QFileSystemMetaData &metaData) -> QByteArray { | 
|---|
| 100 | if (!metaData.exists()) | 
|---|
| 101 | return "a broken symlink"; | 
|---|
| 102 |  | 
|---|
| 103 | QByteArray description; | 
|---|
| 104 | if (metaData.isLink()) | 
|---|
| 105 | description = "a symbolic link to "; | 
|---|
| 106 |  | 
|---|
| 107 | if (metaData.isFile()) | 
|---|
| 108 | description += "a regular file"; | 
|---|
| 109 | else if (metaData.isDirectory()) | 
|---|
| 110 | description += "a directory"; | 
|---|
| 111 | else if (metaData.isSequential()) | 
|---|
| 112 | description += "a character device, socket or FIFO"; | 
|---|
| 113 | else | 
|---|
| 114 | description += "a block device"; | 
|---|
| 115 |  | 
|---|
| 116 | // convert QFileSystemMetaData permissions back to Unix | 
|---|
| 117 | mode_t perms = 0; | 
|---|
| 118 | if (metaData.permissions() & QFile::ReadOwner) | 
|---|
| 119 | perms |= S_IRUSR; | 
|---|
| 120 | if (metaData.permissions() & QFile::WriteOwner) | 
|---|
| 121 | perms |= S_IWUSR; | 
|---|
| 122 | if (metaData.permissions() & QFile::ExeOwner) | 
|---|
| 123 | perms |= S_IXUSR; | 
|---|
| 124 | if (metaData.permissions() & QFile::ReadGroup) | 
|---|
| 125 | perms |= S_IRGRP; | 
|---|
| 126 | if (metaData.permissions() & QFile::WriteGroup) | 
|---|
| 127 | perms |= S_IWGRP; | 
|---|
| 128 | if (metaData.permissions() & QFile::ExeGroup) | 
|---|
| 129 | perms |= S_IXGRP; | 
|---|
| 130 | if (metaData.permissions() & QFile::ReadOther) | 
|---|
| 131 | perms |= S_IROTH; | 
|---|
| 132 | if (metaData.permissions() & QFile::WriteOther) | 
|---|
| 133 | perms |= S_IWOTH; | 
|---|
| 134 | if (metaData.permissions() & QFile::ExeOther) | 
|---|
| 135 | perms |= S_IXOTH; | 
|---|
| 136 | description += " permissions 0"+ QByteArray::number(perms, 8); | 
|---|
| 137 |  | 
|---|
| 138 | return description | 
|---|
| 139 | + " owned by UID "+ QByteArray::number(metaData.userId()) | 
|---|
| 140 | + " GID "+ QByteArray::number(metaData.groupId()); | 
|---|
| 141 | }; | 
|---|
| 142 |  | 
|---|
| 143 | // http://standards.freedesktop.org/basedir-spec/latest/ | 
|---|
| 144 | const uint myUid = uint(geteuid()); | 
|---|
| 145 | const QFile::Permissions wantedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner; | 
|---|
| 146 | const QFileSystemMetaData::MetaDataFlags statFlags = QFileSystemMetaData::PosixStatFlags | 
|---|
| 147 | | QFileSystemMetaData::LinkType; | 
|---|
| 148 | QFileSystemMetaData metaData; | 
|---|
| 149 | QFileSystemEntry entry(xdgRuntimeDir); | 
|---|
| 150 |  | 
|---|
| 151 | // Check that the xdgRuntimeDir is a directory by attempting to create it. | 
|---|
| 152 | // A stat() before mkdir() that concluded it doesn't exist is a meaningless | 
|---|
| 153 | // result: we'd race against someone else attempting to create it. | 
|---|
| 154 | // ### QFileSystemEngine::createDirectory cannot take the extra mode argument. | 
|---|
| 155 | if (QT_MKDIR(entry.nativeFilePath(), 0700) == 0) | 
|---|
| 156 | return true; | 
|---|
| 157 | if (errno != EEXIST) { | 
|---|
| 158 | qErrnoWarning( "QStandardPaths: error creating runtime directory '%ls'", | 
|---|
| 159 | qUtf16Printable(xdgRuntimeDir)); | 
|---|
| 160 | return false; | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | // We use LinkType to force an lstat(), but fillMetaData() still returns error | 
|---|
| 164 | // on broken symlinks. | 
|---|
| 165 | if (!QFileSystemEngine::fillMetaData(entry, metaData, statFlags) && !metaData.isLink()) { | 
|---|
| 166 | qErrnoWarning( "QStandardPaths: error obtaining permissions of runtime directory '%ls'", | 
|---|
| 167 | qUtf16Printable(xdgRuntimeDir)); | 
|---|
| 168 | return false; | 
|---|
| 169 | } | 
|---|
| 170 |  | 
|---|
| 171 | // Checks: | 
|---|
| 172 | // - is a directory | 
|---|
| 173 | // - is not a symlink (even is pointing to a directory) | 
|---|
| 174 | if (metaData.isLink() || !metaData.isDirectory()) { | 
|---|
| 175 | qWarning( "QStandardPaths: runtime directory '%ls' is not a directory, but %s", | 
|---|
| 176 | qUtf16Printable(xdgRuntimeDir), describeMetaData(metaData).constData()); | 
|---|
| 177 | return false; | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | // - "The directory MUST be owned by the user" | 
|---|
| 181 | if (metaData.userId() != myUid) { | 
|---|
| 182 | qWarning( "QStandardPaths: runtime directory '%ls' is not owned by UID %d, but %s", | 
|---|
| 183 | qUtf16Printable(xdgRuntimeDir), myUid, describeMetaData(metaData).constData()); | 
|---|
| 184 | return false; | 
|---|
| 185 | } | 
|---|
| 186 |  | 
|---|
| 187 | // "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700." | 
|---|
| 188 | if (metaData.permissions() != wantedPerms) { | 
|---|
| 189 | // attempt to correct: | 
|---|
| 190 | QSystemError error; | 
|---|
| 191 | if (!QFileSystemEngine::setPermissions(entry, wantedPerms, error)) { | 
|---|
| 192 | qErrnoWarning( "QStandardPaths: could not set correct permissions on runtime directory " | 
|---|
| 193 | "'%ls', which is %s", qUtf16Printable(xdgRuntimeDir), | 
|---|
| 194 | describeMetaData(metaData).constData()); | 
|---|
| 195 | return false; | 
|---|
| 196 | } | 
|---|
| 197 | } | 
|---|
| 198 |  | 
|---|
| 199 | return true; | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | QString QStandardPaths::writableLocation(StandardLocation type) | 
|---|
| 203 | { | 
|---|
| 204 | switch (type) { | 
|---|
| 205 | case HomeLocation: | 
|---|
| 206 | return QDir::homePath(); | 
|---|
| 207 | case TempLocation: | 
|---|
| 208 | return QDir::tempPath(); | 
|---|
| 209 | case CacheLocation: | 
|---|
| 210 | case GenericCacheLocation: | 
|---|
| 211 | { | 
|---|
| 212 | // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html | 
|---|
| 213 | QString xdgCacheHome = QFile::decodeName(qgetenv( "XDG_CACHE_HOME")); | 
|---|
| 214 | if (isTestModeEnabled()) | 
|---|
| 215 | xdgCacheHome = QDir::homePath() + QLatin1String( "/.qttest/cache"); | 
|---|
| 216 | if (xdgCacheHome.isEmpty()) | 
|---|
| 217 | xdgCacheHome = QDir::homePath() + QLatin1String( "/.cache"); | 
|---|
| 218 | if (type == QStandardPaths::CacheLocation) | 
|---|
| 219 | appendOrganizationAndApp(xdgCacheHome); | 
|---|
| 220 | return xdgCacheHome; | 
|---|
| 221 | } | 
|---|
| 222 | case AppDataLocation: | 
|---|
| 223 | case AppLocalDataLocation: | 
|---|
| 224 | case GenericDataLocation: | 
|---|
| 225 | { | 
|---|
| 226 | QString xdgDataHome = QFile::decodeName(qgetenv( "XDG_DATA_HOME")); | 
|---|
| 227 | if (isTestModeEnabled()) | 
|---|
| 228 | xdgDataHome = QDir::homePath() + QLatin1String( "/.qttest/share"); | 
|---|
| 229 | if (xdgDataHome.isEmpty()) | 
|---|
| 230 | xdgDataHome = QDir::homePath() + QLatin1String( "/.local/share"); | 
|---|
| 231 | if (type == AppDataLocation || type == AppLocalDataLocation) | 
|---|
| 232 | appendOrganizationAndApp(xdgDataHome); | 
|---|
| 233 | return xdgDataHome; | 
|---|
| 234 | } | 
|---|
| 235 | case ConfigLocation: | 
|---|
| 236 | case GenericConfigLocation: | 
|---|
| 237 | case AppConfigLocation: | 
|---|
| 238 | { | 
|---|
| 239 | // http://standards.freedesktop.org/basedir-spec/latest/ | 
|---|
| 240 | QString xdgConfigHome = QFile::decodeName(qgetenv( "XDG_CONFIG_HOME")); | 
|---|
| 241 | if (isTestModeEnabled()) | 
|---|
| 242 | xdgConfigHome = QDir::homePath() + QLatin1String( "/.qttest/config"); | 
|---|
| 243 | if (xdgConfigHome.isEmpty()) | 
|---|
| 244 | xdgConfigHome = QDir::homePath() + QLatin1String( "/.config"); | 
|---|
| 245 | if (type == AppConfigLocation) | 
|---|
| 246 | appendOrganizationAndApp(xdgConfigHome); | 
|---|
| 247 | return xdgConfigHome; | 
|---|
| 248 | } | 
|---|
| 249 | case RuntimeLocation: | 
|---|
| 250 | { | 
|---|
| 251 | QString xdgRuntimeDir = QFile::decodeName(qgetenv( "XDG_RUNTIME_DIR")); | 
|---|
| 252 | bool fromEnv = !xdgRuntimeDir.isEmpty(); | 
|---|
| 253 | if (xdgRuntimeDir.isEmpty() || !checkXdgRuntimeDir(xdgRuntimeDir)) { | 
|---|
| 254 | // environment variable not set or is set to something unsuitable | 
|---|
| 255 | const uint myUid = uint(geteuid()); | 
|---|
| 256 | const QString userName = QFileSystemEngine::resolveUserName(myUid); | 
|---|
| 257 | xdgRuntimeDir = QDir::tempPath() + QLatin1String( "/runtime-") + userName; | 
|---|
| 258 |  | 
|---|
| 259 | if (!fromEnv) { | 
|---|
| 260 | #ifndef Q_OS_WASM | 
|---|
| 261 | qWarning( "QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%ls'", qUtf16Printable(xdgRuntimeDir)); | 
|---|
| 262 | #endif | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 | if (!checkXdgRuntimeDir(xdgRuntimeDir)) | 
|---|
| 266 | xdgRuntimeDir.clear(); | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | return xdgRuntimeDir; | 
|---|
| 270 | } | 
|---|
| 271 | default: | 
|---|
| 272 | break; | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | #if QT_CONFIG(regularexpression) | 
|---|
| 276 | // http://www.freedesktop.org/wiki/Software/xdg-user-dirs | 
|---|
| 277 | QString xdgConfigHome = QFile::decodeName(qgetenv( "XDG_CONFIG_HOME")); | 
|---|
| 278 | if (xdgConfigHome.isEmpty()) | 
|---|
| 279 | xdgConfigHome = QDir::homePath() + QLatin1String( "/.config"); | 
|---|
| 280 | QFile file(xdgConfigHome + QLatin1String( "/user-dirs.dirs")); | 
|---|
| 281 | const QLatin1String key = xdg_key_name(type); | 
|---|
| 282 | if (!key.isEmpty() && !isTestModeEnabled() && file.open(QIODevice::ReadOnly)) { | 
|---|
| 283 | QTextStream stream(&file); | 
|---|
| 284 | // Only look for lines like: XDG_DESKTOP_DIR="$HOME/Desktop" | 
|---|
| 285 | QRegularExpression exp(QLatin1String( "^XDG_(.*)_DIR=(.*)$")); | 
|---|
| 286 | QString result; | 
|---|
| 287 | while (!stream.atEnd()) { | 
|---|
| 288 | const QString &line = stream.readLine(); | 
|---|
| 289 | QRegularExpressionMatch match = exp.match(line); | 
|---|
| 290 | if (match.hasMatch() && match.capturedView(1) == key) { | 
|---|
| 291 | QStringView value = match.capturedView(2); | 
|---|
| 292 | if (value.length() > 2 | 
|---|
| 293 | && value.startsWith(QLatin1Char('\"')) | 
|---|
| 294 | && value.endsWith(QLatin1Char('\"'))) | 
|---|
| 295 | value = value.mid(1, value.length() - 2); | 
|---|
| 296 | // value can start with $HOME | 
|---|
| 297 | if (value.startsWith(QLatin1String( "$HOME"))) | 
|---|
| 298 | result = QDir::homePath() + value.mid(5); | 
|---|
| 299 | else | 
|---|
| 300 | result = value.toString(); | 
|---|
| 301 | if (result.length() > 1 && result.endsWith(QLatin1Char('/'))) | 
|---|
| 302 | result.chop(1); | 
|---|
| 303 | } | 
|---|
| 304 | } | 
|---|
| 305 | if (!result.isNull()) | 
|---|
| 306 | return result; | 
|---|
| 307 | } | 
|---|
| 308 | #endif // QT_CONFIG(regularexpression) | 
|---|
| 309 |  | 
|---|
| 310 | QString path; | 
|---|
| 311 | switch (type) { | 
|---|
| 312 | case DesktopLocation: | 
|---|
| 313 | path = QDir::homePath() + QLatin1String( "/Desktop"); | 
|---|
| 314 | break; | 
|---|
| 315 | case DocumentsLocation: | 
|---|
| 316 | path = QDir::homePath() + QLatin1String( "/Documents"); | 
|---|
| 317 | break; | 
|---|
| 318 | case PicturesLocation: | 
|---|
| 319 | path = QDir::homePath() + QLatin1String( "/Pictures"); | 
|---|
| 320 | break; | 
|---|
| 321 |  | 
|---|
| 322 | case FontsLocation: | 
|---|
| 323 | path = writableLocation(GenericDataLocation) + QLatin1String( "/fonts"); | 
|---|
| 324 | break; | 
|---|
| 325 |  | 
|---|
| 326 | case MusicLocation: | 
|---|
| 327 | path = QDir::homePath() + QLatin1String( "/Music"); | 
|---|
| 328 | break; | 
|---|
| 329 |  | 
|---|
| 330 | case MoviesLocation: | 
|---|
| 331 | path = QDir::homePath() + QLatin1String( "/Videos"); | 
|---|
| 332 | break; | 
|---|
| 333 | case DownloadLocation: | 
|---|
| 334 | path = QDir::homePath() + QLatin1String( "/Downloads"); | 
|---|
| 335 | break; | 
|---|
| 336 | case ApplicationsLocation: | 
|---|
| 337 | path = writableLocation(GenericDataLocation) + QLatin1String( "/applications"); | 
|---|
| 338 | break; | 
|---|
| 339 |  | 
|---|
| 340 | default: | 
|---|
| 341 | break; | 
|---|
| 342 | } | 
|---|
| 343 |  | 
|---|
| 344 | return path; | 
|---|
| 345 | } | 
|---|
| 346 |  | 
|---|
| 347 | static QStringList xdgDataDirs() | 
|---|
| 348 | { | 
|---|
| 349 | QStringList dirs; | 
|---|
| 350 | // http://standards.freedesktop.org/basedir-spec/latest/ | 
|---|
| 351 | QString xdgDataDirsEnv = QFile::decodeName(qgetenv( "XDG_DATA_DIRS")); | 
|---|
| 352 | if (xdgDataDirsEnv.isEmpty()) { | 
|---|
| 353 | dirs.append(QString::fromLatin1( "/usr/local/share")); | 
|---|
| 354 | dirs.append(QString::fromLatin1( "/usr/share")); | 
|---|
| 355 | } else { | 
|---|
| 356 | const auto parts = QStringView{xdgDataDirsEnv}.split(QLatin1Char(':'), Qt::SkipEmptyParts); | 
|---|
| 357 |  | 
|---|
| 358 | // Normalize paths, skip relative paths | 
|---|
| 359 | for (const auto &dir : parts) { | 
|---|
| 360 | if (dir.startsWith(QLatin1Char('/'))) | 
|---|
| 361 | dirs.push_back(QDir::cleanPath(dir.toString())); | 
|---|
| 362 | } | 
|---|
| 363 |  | 
|---|
| 364 | // Remove duplicates from the list, there's no use for duplicated | 
|---|
| 365 | // paths in XDG_DATA_DIRS - if it's not found in the given | 
|---|
| 366 | // directory the first time, it won't be there the second time. | 
|---|
| 367 | // Plus duplicate paths causes problems for example for mimetypes, | 
|---|
| 368 | // where duplicate paths here lead to duplicated mime types returned | 
|---|
| 369 | // for a file, eg "text/plain,text/plain" instead of "text/plain" | 
|---|
| 370 | dirs.removeDuplicates(); | 
|---|
| 371 | } | 
|---|
| 372 | return dirs; | 
|---|
| 373 | } | 
|---|
| 374 |  | 
|---|
| 375 | static QStringList xdgConfigDirs() | 
|---|
| 376 | { | 
|---|
| 377 | QStringList dirs; | 
|---|
| 378 | // http://standards.freedesktop.org/basedir-spec/latest/ | 
|---|
| 379 | const QString xdgConfigDirs = QFile::decodeName(qgetenv( "XDG_CONFIG_DIRS")); | 
|---|
| 380 | if (xdgConfigDirs.isEmpty()) | 
|---|
| 381 | dirs.append(QString::fromLatin1( "/etc/xdg")); | 
|---|
| 382 | else | 
|---|
| 383 | dirs = xdgConfigDirs.split(QLatin1Char(':')); | 
|---|
| 384 | return dirs; | 
|---|
| 385 | } | 
|---|
| 386 |  | 
|---|
| 387 | QStringList QStandardPaths::standardLocations(StandardLocation type) | 
|---|
| 388 | { | 
|---|
| 389 | QStringList dirs; | 
|---|
| 390 | switch (type) { | 
|---|
| 391 | case ConfigLocation: | 
|---|
| 392 | case GenericConfigLocation: | 
|---|
| 393 | dirs = xdgConfigDirs(); | 
|---|
| 394 | break; | 
|---|
| 395 | case AppConfigLocation: | 
|---|
| 396 | dirs = xdgConfigDirs(); | 
|---|
| 397 | for (int i = 0; i < dirs.count(); ++i) | 
|---|
| 398 | appendOrganizationAndApp(dirs[i]); | 
|---|
| 399 | break; | 
|---|
| 400 | case GenericDataLocation: | 
|---|
| 401 | dirs = xdgDataDirs(); | 
|---|
| 402 | break; | 
|---|
| 403 | case ApplicationsLocation: | 
|---|
| 404 | dirs = xdgDataDirs(); | 
|---|
| 405 | for (int i = 0; i < dirs.count(); ++i) | 
|---|
| 406 | dirs[i].append(QLatin1String( "/applications")); | 
|---|
| 407 | break; | 
|---|
| 408 | case AppDataLocation: | 
|---|
| 409 | case AppLocalDataLocation: | 
|---|
| 410 | dirs = xdgDataDirs(); | 
|---|
| 411 | for (int i = 0; i < dirs.count(); ++i) | 
|---|
| 412 | appendOrganizationAndApp(dirs[i]); | 
|---|
| 413 | break; | 
|---|
| 414 | case FontsLocation: | 
|---|
| 415 | dirs += QDir::homePath() + QLatin1String( "/.fonts"); | 
|---|
| 416 | dirs += xdgDataDirs(); | 
|---|
| 417 | for (int i = 1; i < dirs.count(); ++i) | 
|---|
| 418 | dirs[i].append(QLatin1String( "/fonts")); | 
|---|
| 419 | break; | 
|---|
| 420 | default: | 
|---|
| 421 | break; | 
|---|
| 422 | } | 
|---|
| 423 | const QString localDir = writableLocation(type); | 
|---|
| 424 | dirs.prepend(localDir); | 
|---|
| 425 | return dirs; | 
|---|
| 426 | } | 
|---|
| 427 |  | 
|---|
| 428 | QT_END_NAMESPACE | 
|---|
| 429 |  | 
|---|
| 430 | #endif // QT_NO_STANDARDPATHS | 
|---|
| 431 |  | 
|---|