/* * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ // local #include "desktopfilereader.h" #include "gscopedpointer.h" #include "logging.h" // Qt #include #include // GIO #include namespace qtmir { DesktopFileReader* DesktopFileReader::Factory::createInstance(const QString &appId, const QFileInfo& fi) { return new DesktopFileReader(appId, fi); } typedef GObjectScopedPointer GAppInfoPointer; struct DesktopFileReaderPrivate { DesktopFileReaderPrivate(DesktopFileReader *parent): q_ptr( parent ) {} QString getKey(const char *key) const { if (!loaded()) return QString(); return QString::fromUtf8(g_desktop_app_info_get_string((GDesktopAppInfo*)appInfo.data(), key)); } bool loaded() const { return !appInfo.isNull(); } DesktopFileReader * const q_ptr; Q_DECLARE_PUBLIC(DesktopFileReader) QString appId; QString file; GAppInfoPointer appInfo; // GAppInfo is actually implemented by GDesktopAppInfo }; DesktopFileReader::DesktopFileReader(const QString &appId, const QFileInfo &desktopFile) : d_ptr(new DesktopFileReaderPrivate(this)) { Q_D(DesktopFileReader); qCDebug(QTMIR_APPLICATIONS) << "Loading desktop file" << desktopFile.absoluteFilePath() << "for appId" << appId; d->appId = appId; d->file = desktopFile.absoluteFilePath(); d->appInfo.reset((GAppInfo*) g_desktop_app_info_new_from_filename(d->file.toUtf8().constData())); if (!d->loaded()) { if (!desktopFile.exists()) { qCWarning(QTMIR_APPLICATIONS) << "Desktop file for appId:" << appId << "at:" << d->file << "does not exist"; } else { qCWarning(QTMIR_APPLICATIONS) << "Desktop file for appId:" << appId << "at:" << d->file << "is not valid - check its syntax, and that the binary specified" << "by the Exec line is installed!"; } } } DesktopFileReader::~DesktopFileReader() { delete d_ptr; } QString DesktopFileReader::file() const { Q_D(const DesktopFileReader); return d->file; } QString DesktopFileReader::appId() const { Q_D(const DesktopFileReader); return d->appId; } QString DesktopFileReader::name() const { Q_D(const DesktopFileReader); if (!d->loaded()) return QString(); return QString::fromUtf8(g_app_info_get_name(d->appInfo.data())); } QString DesktopFileReader::comment() const { Q_D(const DesktopFileReader); if (!d->loaded()) return QString(); return QString::fromUtf8(g_app_info_get_description(d->appInfo.data())); } QString DesktopFileReader::icon() const { Q_D(const DesktopFileReader); return d->getKey("Icon"); } QString DesktopFileReader::exec() const { Q_D(const DesktopFileReader); if (!d->loaded()) return QString(); return QString::fromUtf8(g_app_info_get_commandline(d->appInfo.data())); } QString DesktopFileReader::path() const { Q_D(const DesktopFileReader); return d->getKey("Path"); } QString DesktopFileReader::stageHint() const { Q_D(const DesktopFileReader); return d->getKey("X-Ubuntu-StageHint"); } QString DesktopFileReader::splashTitle() const { Q_D(const DesktopFileReader); if (!d->loaded()) return QString(); /* Sadly GDesktopAppInfo only considers Name, GenericName, Comments and Keywords to be keys * which can have locale-specific entries. So we need to work to make X-Ubuntu-Splash-Title * locale-aware, by generating a locale-correct key name and seeing if that exists. If yes, * get the value and return it. Else fallback to the non-localized value. */ GDesktopAppInfo *info = (GDesktopAppInfo*)d->appInfo.data(); QLocale defaultLocale; QStringList locales = defaultLocale.uiLanguages(); QString keyTemplate("X-Ubuntu-Splash-Title[%1]"); for (QString locale: locales) { // Desktop files use local specifiers with underscore separators but Qt uses hyphens locale = locale.replace('-', '_'); const char* key = keyTemplate.arg(locale).toUtf8().constData(); if (g_desktop_app_info_has_key(info, key)) { return d->getKey(key); } } // Fallback to the non-localized string, if available return d->getKey("X-Ubuntu-Splash-Title"); } QString DesktopFileReader::splashImage() const { Q_D(const DesktopFileReader); return d->getKey("X-Ubuntu-Splash-Image"); } QString DesktopFileReader::splashShowHeader() const { Q_D(const DesktopFileReader); return d->getKey("X-Ubuntu-Splash-Show-Header"); } QString DesktopFileReader::splashColor() const { Q_D(const DesktopFileReader); return d->getKey("X-Ubuntu-Splash-Color"); } QString DesktopFileReader::splashColorHeader() const { Q_D(const DesktopFileReader); return d->getKey("X-Ubuntu-Splash-Color-Header"); } QString DesktopFileReader::splashColorFooter() const { Q_D(const DesktopFileReader); return d->getKey("X-Ubuntu-Splash-Color-Footer"); } Qt::ScreenOrientations DesktopFileReader::supportedOrientations() const { Q_D(const DesktopFileReader); Qt::ScreenOrientations result; if (!parseOrientations(d->getKey("X-Ubuntu-Supported-Orientations"), result)) { qCWarning(QTMIR_APPLICATIONS) << d->file << "has an invalid X-Ubuntu-Supported-Orientations entry."; } return result; } bool DesktopFileReader::rotatesWindowContents() const { Q_D(const DesktopFileReader); bool result; if (!parseBoolean(d->getKey("X-Ubuntu-Rotates-Window-Contents"), result)) { qCWarning(QTMIR_APPLICATIONS) << d->file << "has an invalid X-Ubuntu-Rotates-Window-Contents entry."; } return result; } bool DesktopFileReader::parseOrientations(const QString &rawString, Qt::ScreenOrientations &result) { // Default to all orientations result = Qt::PortraitOrientation | Qt::LandscapeOrientation | Qt::InvertedPortraitOrientation | Qt::InvertedLandscapeOrientation; if (rawString.isEmpty()) { return true; } Qt::ScreenOrientations parsedOrientations = 0; bool ok = true; QStringList orientationsList = rawString .simplified() .replace(QChar(','), ";") .remove(QChar(' ')) .remove(QChar('-')) .remove(QChar('_')) .toLower() .split(";"); for (int i = 0; i < orientationsList.count() && ok; ++i) { const QString &orientationString = orientationsList.at(i); if (orientationString.isEmpty()) { // skip it continue; } if (orientationString == "portrait") { parsedOrientations |= Qt::PortraitOrientation; } else if (orientationString == "landscape") { parsedOrientations |= Qt::LandscapeOrientation; } else if (orientationString == "invertedportrait") { parsedOrientations |= Qt::InvertedPortraitOrientation; } else if (orientationString == "invertedlandscape") { parsedOrientations |= Qt::InvertedLandscapeOrientation; } else if (orientationsList.count() == 1 && orientationString == "primary") { // Special case: primary orientation must be alone // There's no sense in supporting primary orientation + other orientations // like "primary,landscape" parsedOrientations = Qt::PrimaryOrientation; } else { ok = false; } } if (ok) { result = parsedOrientations; } return ok; } bool DesktopFileReader::parseBoolean(const QString &rawString, bool &result) { QString cookedString = rawString.trimmed().toLower(); result = cookedString == "y" || cookedString == "1" || cookedString == "yes" || cookedString == "true"; return result || rawString.isEmpty() || cookedString == "n" || cookedString == "0" || cookedString == "no" || cookedString == "false"; } bool DesktopFileReader::loaded() const { Q_D(const DesktopFileReader); return d->loaded(); } } // namespace qtmir