From a9731e37875d0f5e9f875a583ec46153d0c913f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Sat, 17 Aug 2024 03:16:35 +0200 Subject: [PATCH] Linux Portable: add proper desktop integration The Linux portable will now ask if you want to integrate Friction with your desktop environment. A better solution than using AppImage IMHO. The portable will now integrate with the desktop and offer true portability with settings etc located in the same folder as the app. TODO: add "uninstall". --- src/app/main.cpp | 15 +++ src/app/resources.qrc | 3 + src/app/xdg/friction.desktop | 13 +++ src/app/xdg/friction.xml | 7 ++ src/core/appsupport.cpp | 180 +++++++++++++++++++++++++++++++++++ src/core/appsupport.h | 2 + 6 files changed, 220 insertions(+) create mode 100644 src/app/xdg/friction.desktop create mode 100644 src/app/xdg/friction.xml diff --git a/src/app/main.cpp b/src/app/main.cpp index 6f586ad66..1e7279716 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -197,6 +197,21 @@ int main(int argc, char *argv[]) ThemeSupport::setupTheme(eSizesUI::widget); +#ifdef Q_OS_LINUX + if (AppSupport::isAppPortable()) { + if (!AppSupport::hasXDGDesktopIntegration()) { + const auto ask = QMessageBox::question(nullptr, + QObject::tr("Setup Desktop Integration?"), + QObject::tr("Would you like to setup desktop integration?" + " This will add Friction to your application launcher" + " and add mime type for project files.")); + if (ask == QMessageBox::Yes) { + AppSupport::setupXDGDesktopIntegration(); + } + } + } +#endif + //#ifdef QT_DEBUG // const qint64 pId = QCoreApplication::applicationPid(); // QProcess * const process = new QProcess(&w); diff --git a/src/app/resources.qrc b/src/app/resources.qrc index 01f1a133b..c5cc628e1 100644 --- a/src/app/resources.qrc +++ b/src/app/resources.qrc @@ -32,5 +32,8 @@ presets/render/003-friction-preset-prores-444.conf presets/render/002-friction-preset-mp4-h264-mp3.conf presets/render/001-friction-preset-mp4-h264.conf + xdg/friction.xml + xdg/friction.desktop + icons/hicolor/scalable/apps/graphics.friction.Friction.svg diff --git a/src/app/xdg/friction.desktop b/src/app/xdg/friction.desktop new file mode 100644 index 000000000..ba55d1e86 --- /dev/null +++ b/src/app/xdg/friction.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Version=1.0 +Name=Friction +Exec=__FRICTION__ %f +Icon=graphics.friction.Friction +Comment=Motion graphics and animation +GenericName=Friction Graphics +StartupNotify=true +Terminal=false +Type=Application +Categories=Graphics; +MimeType=application/x-graphics.friction.Friction; +StartupWMClass=friction diff --git a/src/app/xdg/friction.xml b/src/app/xdg/friction.xml new file mode 100644 index 000000000..2c4f9523c --- /dev/null +++ b/src/app/xdg/friction.xml @@ -0,0 +1,7 @@ + + + + Friction + + + diff --git a/src/core/appsupport.cpp b/src/core/appsupport.cpp index 776ee54cd..051850e0e 100644 --- a/src/core/appsupport.cpp +++ b/src/core/appsupport.cpp @@ -682,3 +682,183 @@ bool AppSupport::isAppPortable() { return QFile::exists(QString("%1/portable.txt").arg(getAppPath())); } + +bool AppSupport::hasXDGDesktopIntegration() +{ + QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); + if (path.isEmpty() || + !path.startsWith(QDir::homePath())) { path = QString("%1/.local/share").arg(QDir::homePath()); } + + QStringList files; + QString desktop = "applications/graphics.friction.Friction.desktop"; + files << desktop; + files << "mime/packages/graphics.friction.Friction.xml"; + files << "icons/hicolor/scalable/apps/graphics.friction.Friction.svg"; + files << "icons/hicolor/256x256/apps/graphics.friction.Friction.png"; + files << "icons/hicolor/scalable/mimetypes/application-x-graphics.friction.Friction.svg"; + files << "icons/hicolor/256x256/mimetypes/application-x-graphics.friction.Friction.png"; + + for (const auto &file : files) { + if (!QFile::exists(QString("%1/%2").arg(path, file))) { + qDebug() << "not found!" << file; + return false; + } + } + + QString desktopFilePath(QString("%1/%2").arg(path, desktop)); + if (QFile::exists(desktopFilePath)) { + QSettings dotDesktop(desktopFilePath, QSettings::IniFormat); + dotDesktop.beginGroup("Desktop Entry"); + QString exec = dotDesktop.value("Exec").toString().simplified(); + dotDesktop.endGroup(); + if (exec.isEmpty() || !exec.startsWith(getAppPath())) { return false; } + } + return true; +} + +bool AppSupport::setupXDGDesktopIntegration() +{ + QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); + if (path.isEmpty() || + !path.startsWith(QDir::homePath())) { path = QString("%1/.local/share").arg(QDir::homePath()); } + + if (!QFile::exists(path)) { + QDir dir(path); + if (!dir.mkpath(path)) { return false; } + } + + const QString resDesktop = ":/xdg/friction.desktop"; + const QString resMime = ":/xdg/friction.xml"; + const QString resSvg = ":/icons/hicolor/scalable/apps/graphics.friction.Friction.svg"; + const QString resPng = ":/icons/hicolor/256x256/apps/graphics.friction.Friction.png"; + + { + const QString dirName(QString("%1/applications").arg(path)); + const QString fileName(QString("%1/graphics.friction.Friction.desktop").arg(dirName)); + qDebug() << "Checking:" << fileName; + if (!QFile::exists(dirName)) { + QDir dir(dirName); + if (!dir.mkpath(dirName)) { return false; } + } + bool wrongPath = false; + QSettings desktop(fileName, QSettings::IniFormat); + desktop.beginGroup("Desktop Entry"); + QString exec = desktop.value("Exec").toString().simplified(); + if (!exec.startsWith(getAppPath())) { wrongPath = true; } + desktop.endGroup(); + if (!QFile::exists(fileName) || wrongPath) { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { + QFile res(resDesktop); + if (res.open(QIODevice::ReadOnly | QIODevice::Text)) { + file.write(res.readAll().replace("__FRICTION__", + qApp->applicationFilePath().toUtf8())); + res.close(); + } else { return false; } + file.close(); + } else { return false; } + } + } + { + const QString dirName(QString("%1/mime/packages").arg(path)); + const QString fileName(QString("%1/graphics.friction.Friction.xml").arg(dirName)); + qDebug() << "Checking:" << fileName; + if (!QFile::exists(dirName)) { + QDir dir(dirName); + if (!dir.mkpath(dirName)) { return false; } + } + if (!QFile::exists(fileName)) { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QFile res(resMime); + if (res.open(QIODevice::ReadOnly | QIODevice::Text)) { + file.write(res.readAll()); + res.close(); + } else { return false; } + file.close(); + } else { return false; } + } + } + { + const QString dirName(QString("%1/icons/hicolor/scalable/apps").arg(path)); + const QString fileName(QString("%1/graphics.friction.Friction.svg").arg(dirName)); + qDebug() << "Checking:" << fileName; + if (!QFile::exists(dirName)) { + QDir dir(dirName); + if (!dir.mkpath(dirName)) { return false; } + } + if (!QFile::exists(fileName)) { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QFile res(resSvg); + if (res.open(QIODevice::ReadOnly | QIODevice::Text)) { + file.write(res.readAll()); + res.close(); + } else { return false; } + file.close(); + } else { return false; } + } + } + { + const QString dirName(QString("%1/icons/hicolor/256x256/apps").arg(path)); + const QString fileName(QString("%1/graphics.friction.Friction.png").arg(dirName)); + qDebug() << "Checking:" << fileName; + if (!QFile::exists(dirName)) { + QDir dir(dirName); + if (!dir.mkpath(dirName)) { return false; } + } + if (!QFile::exists(fileName)) { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + QFile res(resPng); + if (res.open(QIODevice::ReadOnly)) { + file.write(res.readAll()); + res.close(); + } else { return false; } + file.close(); + } else { return false; } + } + } + { + const QString dirName(QString("%1/icons/hicolor/scalable/mimetypes").arg(path)); + const QString fileName(QString("%1/application-x-graphics.friction.Friction.svg").arg(dirName)); + qDebug() << "Checking:" << fileName; + if (!QFile::exists(dirName)) { + QDir dir(dirName); + if (!dir.mkpath(dirName)) { return false; } + } + if (!QFile::exists(fileName)) { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QFile res(resSvg); + if (res.open(QIODevice::ReadOnly | QIODevice::Text)) { + file.write(res.readAll()); + res.close(); + } else { return false; } + file.close(); + } else { return false; } + } + } + { + const QString dirName(QString("%1/icons/hicolor/256x256/mimetypes").arg(path)); + const QString fileName(QString("%1/application-x-graphics.friction.Friction.png").arg(dirName)); + qDebug() << dirName << fileName; + if (!QFile::exists(dirName)) { + QDir dir(dirName); + if (!dir.mkpath(dirName)) { return false; } + } + if (!QFile::exists(fileName)) { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + QFile res(resPng); + if (res.open(QIODevice::ReadOnly)) { + file.write(res.readAll()); + res.close(); + } else { return false; } + file.close(); + } else { return false; } + } + } + + return true; +} diff --git a/src/core/appsupport.h b/src/core/appsupport.h index 7f1514313..607cdccf6 100644 --- a/src/core/appsupport.h +++ b/src/core/appsupport.h @@ -119,6 +119,8 @@ class CORE_EXPORT AppSupport : public QObject static int getProjectVersion(const QString &fileName = QString()); static const QPair hasWriteAccess(); static bool isAppPortable(); + static bool hasXDGDesktopIntegration(); + static bool setupXDGDesktopIntegration(); }; #endif // APPSUPPORT_H