fix: introduce new DesktopFile class
KeyFile::saveToFile not guaranteed section order, which is not the right behavior of desktop file. XDG requires the first section of desktop file always to be "Desktop Entry". So I write a new DesktopFile class, which override the saveToFile method of KeyFile, to make it work. close linuxdeepin/developer-center#3807 Signed-off-by: black-desk <me@black-desk.cn>
This commit is contained in:
parent
abf322377e
commit
accc9c2aac
42
src/lib/desktopfile.cpp
Normal file
42
src/lib/desktopfile.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "desktopfile.h"
|
||||
|
||||
DesktopFile::DesktopFile(char separtor)
|
||||
: KeyFile(separtor)
|
||||
{
|
||||
}
|
||||
|
||||
DesktopFile::~DesktopFile() = default;
|
||||
|
||||
bool DesktopFile::saveToFile(const std::string &filePath){
|
||||
FILE *sfp = fopen(filePath.data(), "w+");
|
||||
if (!sfp) {
|
||||
perror("open file failed...");
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE(black_desk): XDG require the first section of desktop file
|
||||
// is always "Desktop Entry"
|
||||
|
||||
auto mainSection = m_mainKeyMap.find("Desktop Entry");
|
||||
if (mainSection != m_mainKeyMap.end()) {
|
||||
// FIXME(black_desk): should handle write fail.
|
||||
writeSectionToFile(mainSection->first, mainSection->second, sfp);
|
||||
} else {
|
||||
// FIXME(black_desk): should have some warning.
|
||||
}
|
||||
|
||||
for (const auto &im : m_mainKeyMap) {
|
||||
if (im.first == "Desktop Entry") {
|
||||
continue;
|
||||
}
|
||||
// FIXME(black_desk): should handle write fail.
|
||||
writeSectionToFile(im.first, im.second, sfp);
|
||||
}
|
||||
|
||||
fclose(sfp);
|
||||
return true;
|
||||
}
|
24
src/lib/desktopfile.h
Normal file
24
src/lib/desktopfile.h
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef DESKTOPFILE_H
|
||||
#define DESKTOPFILE_H
|
||||
|
||||
#include "keyfile.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
// 解析desktop文件类
|
||||
class DesktopFile: public KeyFile
|
||||
{
|
||||
public:
|
||||
explicit DesktopFile(char separtor = ';');
|
||||
virtual ~DesktopFile();
|
||||
|
||||
virtual bool saveToFile(const std::string &filePath) override;
|
||||
};
|
||||
|
||||
#endif // DESKTOPFILE_H
|
@ -20,7 +20,7 @@ std::vector<std::string> DesktopInfo::currentDesktops;
|
||||
|
||||
DesktopInfo::DesktopInfo(const std::string &_fileName)
|
||||
: m_isValid(true)
|
||||
, m_keyFile(KeyFile())
|
||||
, m_desktopFile()
|
||||
{
|
||||
std::string fileNameWithSuffix(_fileName);
|
||||
if (!DString::endWith(_fileName, ".desktop"))
|
||||
@ -45,10 +45,10 @@ DesktopInfo::DesktopInfo(const std::string &_fileName)
|
||||
}
|
||||
}
|
||||
|
||||
m_keyFile.loadFile(m_fileName);
|
||||
m_desktopFile.loadFile(m_fileName);
|
||||
|
||||
// check DesktopInfo valid
|
||||
std::vector<std::string> mainKeys = m_keyFile.getMainKeys();
|
||||
std::vector<std::string> mainKeys = m_desktopFile.getMainKeys();
|
||||
if (mainKeys.size() == 0)
|
||||
m_isValid = false;
|
||||
|
||||
@ -58,11 +58,11 @@ DesktopInfo::DesktopInfo(const std::string &_fileName)
|
||||
if (!found)
|
||||
m_isValid = false;
|
||||
|
||||
if (m_keyFile.getStr(MainSection, KeyType) != TypeApplication)
|
||||
if (m_desktopFile.getStr(MainSection, KeyType) != TypeApplication)
|
||||
m_isValid = false;
|
||||
|
||||
m_name = m_keyFile.getLocaleStr(MainSection, KeyName, "");
|
||||
m_icon = m_keyFile.getStr(MainSection, KeyIcon);
|
||||
m_name = m_desktopFile.getLocaleStr(MainSection, KeyName, "");
|
||||
m_icon = m_desktopFile.getStr(MainSection, KeyIcon);
|
||||
m_id = getId();
|
||||
}
|
||||
|
||||
@ -98,12 +98,12 @@ bool DesktopInfo::shouldShow()
|
||||
|
||||
bool DesktopInfo::getNoDisplay()
|
||||
{
|
||||
return m_keyFile.getBool(MainSection, KeyNoDisplay);
|
||||
return m_desktopFile.getBool(MainSection, KeyNoDisplay);
|
||||
}
|
||||
|
||||
bool DesktopInfo::getIsHidden()
|
||||
{
|
||||
return m_keyFile.getBool(MainSection, KeyHidden);
|
||||
return m_desktopFile.getBool(MainSection, KeyHidden);
|
||||
}
|
||||
|
||||
bool DesktopInfo::getShowIn(std::vector<std::string> desktopEnvs)
|
||||
@ -119,8 +119,8 @@ bool DesktopInfo::getShowIn(std::vector<std::string> desktopEnvs)
|
||||
desktopEnvs.assign(currentDesktops.begin(), currentDesktops.end());
|
||||
}
|
||||
|
||||
std::vector<std::string> onlyShowIn = m_keyFile.getStrList(MainSection, KeyOnlyShowIn);
|
||||
std::vector<std::string> notShowIn = m_keyFile.getStrList(MainSection, KeyNotShowIn);
|
||||
std::vector<std::string> onlyShowIn = m_desktopFile.getStrList(MainSection, KeyOnlyShowIn);
|
||||
std::vector<std::string> notShowIn = m_desktopFile.getStrList(MainSection, KeyNotShowIn);
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
auto strVector2qstrVector = [](const std::vector<std::string> &vector) {
|
||||
@ -159,7 +159,7 @@ bool DesktopInfo::getShowIn(std::vector<std::string> desktopEnvs)
|
||||
|
||||
std::string DesktopInfo::getExecutable()
|
||||
{
|
||||
return m_keyFile.getStr(MainSection, KeyExec);
|
||||
return m_desktopFile.getStr(MainSection, KeyExec);
|
||||
}
|
||||
|
||||
bool DesktopInfo::isExecutableOk()
|
||||
@ -213,12 +213,12 @@ bool DesktopInfo::isDesktopAction(std::string name)
|
||||
std::vector<DesktopAction> DesktopInfo::getActions()
|
||||
{
|
||||
std::vector<DesktopAction> actions;
|
||||
for (const auto &mainKey : m_keyFile.getMainKeys()) {
|
||||
for (const auto &mainKey : m_desktopFile.getMainKeys()) {
|
||||
if (DString::startWith(mainKey, "Desktop Action")
|
||||
|| DString::endWith(mainKey, "Shortcut Group")) {
|
||||
DesktopAction action;
|
||||
action.name = m_keyFile.getLocaleStr(mainKey, KeyName, "");
|
||||
action.exec = m_keyFile.getStr(mainKey, KeyExec);
|
||||
action.name = m_desktopFile.getLocaleStr(mainKey, KeyName, "");
|
||||
action.exec = m_desktopFile.getStr(mainKey, KeyExec);
|
||||
action.section = mainKey;
|
||||
actions.push_back(action);
|
||||
}
|
||||
@ -246,13 +246,13 @@ DesktopInfo DesktopInfo::getDesktopInfoById(std::string appId)
|
||||
|
||||
bool DesktopInfo::getTerminal()
|
||||
{
|
||||
return m_keyFile.getBool(MainSection, KeyTerminal);
|
||||
return m_desktopFile.getBool(MainSection, KeyTerminal);
|
||||
}
|
||||
|
||||
// TryExec is Path to an executable file on disk used to determine if the program is actually installed
|
||||
std::string DesktopInfo::getTryExec()
|
||||
{
|
||||
return m_keyFile.getStr(MainSection, KeyTryExec);
|
||||
return m_desktopFile.getStr(MainSection, KeyTryExec);
|
||||
}
|
||||
|
||||
// 按$PATH路径查找执行文件
|
||||
@ -301,7 +301,7 @@ std::string DesktopInfo::getId()
|
||||
|
||||
std::string DesktopInfo::getGenericName()
|
||||
{
|
||||
return m_keyFile.getLocaleStr(MainSection, KeyGenericName, "");
|
||||
return m_desktopFile.getLocaleStr(MainSection, KeyGenericName, "");
|
||||
}
|
||||
|
||||
std::string DesktopInfo::getName()
|
||||
@ -316,17 +316,17 @@ std::string DesktopInfo::getIcon()
|
||||
|
||||
std::string DesktopInfo::getCommandLine()
|
||||
{
|
||||
return m_keyFile.getStr(MainSection, KeyExec);
|
||||
return m_desktopFile.getStr(MainSection, KeyExec);
|
||||
}
|
||||
|
||||
std::vector<std::string> DesktopInfo::getKeywords()
|
||||
{
|
||||
return m_keyFile.getLocaleStrList(MainSection, KeyKeywords, "");
|
||||
return m_desktopFile.getLocaleStrList(MainSection, KeyKeywords, "");
|
||||
}
|
||||
|
||||
std::vector<std::string> DesktopInfo::getCategories()
|
||||
{
|
||||
return m_keyFile.getStrList(MainSection, KeyCategories);
|
||||
return m_desktopFile.getStrList(MainSection, KeyCategories);
|
||||
}
|
||||
|
||||
void DesktopInfo::setDesktopOverrideExec(const std::string &execStr)
|
||||
@ -334,9 +334,9 @@ void DesktopInfo::setDesktopOverrideExec(const std::string &execStr)
|
||||
m_overRideExec = execStr;
|
||||
}
|
||||
|
||||
KeyFile *DesktopInfo::getKeyFile()
|
||||
DesktopFile *DesktopInfo::getDesktopFile()
|
||||
{
|
||||
return &m_keyFile;
|
||||
return &m_desktopFile;
|
||||
}
|
||||
|
||||
// class AppsDir
|
||||
|
@ -5,7 +5,7 @@
|
||||
#ifndef DESKTOPINFO_H
|
||||
#define DESKTOPINFO_H
|
||||
|
||||
#include "keyfile.h"
|
||||
#include "desktopfile.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -82,7 +82,7 @@ public:
|
||||
std::vector<std::string> getCategories();
|
||||
void setDesktopOverrideExec(const std::string &execStr);
|
||||
|
||||
KeyFile *getKeyFile();
|
||||
DesktopFile *getDesktopFile();
|
||||
|
||||
private:
|
||||
std::string getTryExec();
|
||||
@ -96,7 +96,7 @@ private:
|
||||
std::string m_icon;
|
||||
std::string m_overRideExec;
|
||||
bool m_isValid;
|
||||
KeyFile m_keyFile;
|
||||
DesktopFile m_desktopFile;
|
||||
};
|
||||
|
||||
// 应用目录类
|
||||
|
@ -177,12 +177,8 @@ bool KeyFile::saveToFile(const std::string &filePath)
|
||||
}
|
||||
|
||||
for (const auto &im : m_mainKeyMap) {
|
||||
const auto &keyMap = im.second;
|
||||
std::string section = "[" + im.first + "]\n";
|
||||
fputs(section.c_str(), sfp);
|
||||
for (const auto &ik : keyMap) {
|
||||
std::string kv = ik.first + "=" + ik.second + "\n";
|
||||
fputs(kv.c_str(), sfp);
|
||||
if (!writeSectionToFile(im.first, im.second,sfp)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,6 +186,22 @@ bool KeyFile::saveToFile(const std::string &filePath)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyFile::writeSectionToFile(const std::string& sectionName, const KeyMap& keyMap, FILE * file){
|
||||
if (file == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string section = "[" + sectionName + "]\n";
|
||||
fputs(section.c_str(), file);
|
||||
for (const auto &ik : keyMap) {
|
||||
std::string kv = ik.first + "=" + ik.second + "\n";
|
||||
fputs(kv.c_str(), file);
|
||||
}
|
||||
|
||||
// FIXME(black_desk): should handle fputs error
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyFile::loadFile(const std::string &filePath)
|
||||
{
|
||||
m_mainKeyMap.clear();
|
||||
|
@ -12,12 +12,12 @@
|
||||
typedef std::map<std::string, std::string> KeyMap;
|
||||
typedef std::map<std::string, KeyMap> MainKeyMap;
|
||||
|
||||
// 解析ini、desktop文件类
|
||||
// 解析ini文件类
|
||||
class KeyFile
|
||||
{
|
||||
public:
|
||||
explicit KeyFile(char separtor = ';');
|
||||
~KeyFile();
|
||||
virtual ~KeyFile();
|
||||
|
||||
bool getBool(const std::string §ion, const std::string &key, bool defaultValue = false);
|
||||
void setBool(const std::string §ion, const std::string &key, const std::string &defaultValue = "false");
|
||||
@ -34,7 +34,7 @@ public:
|
||||
std::vector<std::string> getLocaleStrList(const std::string §ion, const std::string &key, std::string defaultLocale = "");
|
||||
|
||||
void setKey(const std::string §ion, const std::string &key, const std::string &value);
|
||||
bool saveToFile(const std::string &filePath);
|
||||
virtual bool saveToFile(const std::string &filePath);
|
||||
bool loadFile(const std::string &filePath);
|
||||
std::vector<std::string> getMainKeys();
|
||||
std::string getFilePath()
|
||||
@ -45,12 +45,14 @@ public:
|
||||
// for test
|
||||
void print();
|
||||
|
||||
private:
|
||||
protected:
|
||||
MainKeyMap m_mainKeyMap; // section -> key : value
|
||||
std::string m_filePath;
|
||||
FILE *m_fp;
|
||||
bool m_modified;
|
||||
char m_listSeparator;
|
||||
|
||||
static bool writeSectionToFile(const std::string& sectionName, const KeyMap& keyMap, FILE * file);
|
||||
};
|
||||
|
||||
#endif // KEYFILE_H
|
||||
|
@ -29,7 +29,7 @@ void AppInfo::init(DesktopInfo &info)
|
||||
return;
|
||||
}
|
||||
|
||||
std::string xDeepinVendor= info.getKeyFile()->getStr(MainSection, "X-Deepin-Vendor");
|
||||
std::string xDeepinVendor= info.getDesktopFile()->getStr(MainSection, "X-Deepin-Vendor");
|
||||
if (xDeepinVendor == "deepin") {
|
||||
m_name = info.getGenericName().c_str();
|
||||
if (m_name.isEmpty())
|
||||
|
@ -247,9 +247,9 @@ bool Launcher::requestSendToDesktop(QString appId)
|
||||
|
||||
// 创建桌面快捷方式文件
|
||||
DesktopInfo dinfo(itemsMap[appId].info.path.toStdString());
|
||||
dinfo.getKeyFile()->setKey(MainSection, dbusService.toStdString(), "X-Deepin-CreatedBy");
|
||||
dinfo.getKeyFile()->setKey(MainSection, appId.toStdString(), "X-Deepin-AppID");
|
||||
if (!dinfo.getKeyFile()->saveToFile(filePath.toStdString()))
|
||||
dinfo.getDesktopFile()->setKey(MainSection, dbusService.toStdString(), "X-Deepin-CreatedBy");
|
||||
dinfo.getDesktopFile()->setKey(MainSection, appId.toStdString(), "X-Deepin-AppID");
|
||||
if (!dinfo.getDesktopFile()->saveToFile(filePath.toStdString()))
|
||||
return false;
|
||||
|
||||
// 播放音频
|
||||
@ -907,7 +907,7 @@ AppType Launcher::getAppType(DesktopInfo &info, const Item &item)
|
||||
QFileInfo fileInfo;
|
||||
// 判断是否为flatpak应用
|
||||
do {
|
||||
if (!info.getKeyFile()->containKey(MainSection, "X-Flatpak"))
|
||||
if (!info.getDesktopFile()->containKey(MainSection, "X-Flatpak"))
|
||||
break;
|
||||
|
||||
std::vector<std::string> parts = DString::splitStr(info.getCommandLine(), ' ');
|
||||
@ -946,7 +946,7 @@ AppType Launcher::getAppType(DesktopInfo &info, const Item &item)
|
||||
|
||||
// 判断是否为wineApp
|
||||
do {
|
||||
std::string createdBy = info.getKeyFile()->getStr(MainSection, "X-Created-By");
|
||||
std::string createdBy = info.getDesktopFile()->getStr(MainSection, "X-Created-By");
|
||||
if (DString::startWith(createdBy, "cxoffice-") || strstr(info.getCommandLine().c_str(), "env WINEPREFIX=")) {
|
||||
ty = AppType::WineApp;
|
||||
goto end;
|
||||
@ -1184,10 +1184,10 @@ bool Launcher::isDeepinCustomDesktopFile(QString fileName)
|
||||
|
||||
Item Launcher::NewItemWithDesktopInfo(DesktopInfo &info)
|
||||
{
|
||||
QString enName(info.getKeyFile()->getStr(MainSection, KeyName).c_str());
|
||||
QString enComment(info.getKeyFile()->getStr(MainSection, KeyComment).c_str());
|
||||
QString xDeepinCategory(info.getKeyFile()->getStr(MainSection, "X-Deepin-Category").c_str());
|
||||
QString xDeepinVendor(info.getKeyFile()->getStr(MainSection, "X-Deepin-Vendor").c_str());
|
||||
QString enName(info.getDesktopFile()->getStr(MainSection, KeyName).c_str());
|
||||
QString enComment(info.getDesktopFile()->getStr(MainSection, KeyComment).c_str());
|
||||
QString xDeepinCategory(info.getDesktopFile()->getStr(MainSection, "X-Deepin-Category").c_str());
|
||||
QString xDeepinVendor(info.getDesktopFile()->getStr(MainSection, "X-Deepin-Vendor").c_str());
|
||||
|
||||
QString appName;
|
||||
if (xDeepinVendor == "deepin")
|
||||
|
@ -343,7 +343,7 @@ bool StartManager::doLaunchAppWithOptions(QString desktopFile, uint32_t timestam
|
||||
}
|
||||
|
||||
if (options.find("path") != options.end()) {
|
||||
info.getKeyFile()->setKey(MainSection, KeyPath, options["path"].toString().toStdString());
|
||||
info.getDesktopFile()->setKey(MainSection, KeyPath, options["path"].toString().toStdString());
|
||||
}
|
||||
|
||||
if (options.find("desktop-override-exec") != options.end()) {
|
||||
@ -433,7 +433,7 @@ bool StartManager::launch(DesktopInfo *info, QString cmdLine, uint32_t timestamp
|
||||
exeArgs.insert(0, SETTING->getDefaultTerminalExec());
|
||||
}
|
||||
|
||||
std::string workingDir = info->getKeyFile()->getStr(MainSection, KeyPath);
|
||||
std::string workingDir = info->getDesktopFile()->getStr(MainSection, KeyPath);
|
||||
if (workingDir.empty()) {
|
||||
workingDir = BaseDir::homeDir();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user