2022-04-24 14:52:13 +08:00
|
|
|
|
/*
|
2022-05-15 12:10:42 +08:00
|
|
|
|
* Copyright (C) 2021 ~ 2022 Deepin Technology Co., Ltd.
|
2022-04-24 14:52:13 +08:00
|
|
|
|
*
|
|
|
|
|
* Author: weizhixiang <weizhixiang@uniontech.com>
|
|
|
|
|
*
|
|
|
|
|
* Maintainer: weizhixiang <weizhixiang@uniontech.com>
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "desktopinfo.h"
|
|
|
|
|
#include "locale.h"
|
|
|
|
|
#include "unistd.h"
|
|
|
|
|
#include "dstring.h"
|
|
|
|
|
#include "dfile.h"
|
|
|
|
|
#include "basedir.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> DesktopInfo::currentDesktops;
|
|
|
|
|
|
|
|
|
|
DesktopInfo::DesktopInfo(const std::string &_fileName)
|
2022-05-15 12:10:42 +08:00
|
|
|
|
: m_isValid(true)
|
|
|
|
|
, m_keyFile(KeyFile())
|
2022-04-24 14:52:13 +08:00
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
std::string fileNameWithSuffix(_fileName);
|
|
|
|
|
if (!DString::endWith(_fileName, ".desktop"))
|
|
|
|
|
fileNameWithSuffix += ".desktop";
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_fileName = fileNameWithSuffix;
|
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
if (DFile::dir(m_fileName).empty()) {
|
2022-04-24 14:52:13 +08:00
|
|
|
|
// fileName是文件名,增加目录
|
|
|
|
|
bool isExisted = false;
|
|
|
|
|
for (const auto &dir : BaseDir::appDirs()) {
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_fileName = dir + fileNameWithSuffix;
|
|
|
|
|
if (DFile::isExisted(m_fileName)) {
|
2022-04-24 14:52:13 +08:00
|
|
|
|
isExisted = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isExisted) {
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_isValid = false;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_keyFile.loadFile(m_fileName);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
|
|
// check DesktopInfo valid
|
2022-05-15 12:10:42 +08:00
|
|
|
|
std::vector<std::string> mainKeys = m_keyFile.getMainKeys();
|
2022-04-24 14:52:13 +08:00
|
|
|
|
if (mainKeys.size() == 0)
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_isValid = false;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
|
|
bool found = std::any_of(mainKeys.begin(), mainKeys.end(),
|
|
|
|
|
[](const auto &key) {return key == MainSection;});
|
|
|
|
|
|
|
|
|
|
if (!found)
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_isValid = false;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
if (m_keyFile.getStr(MainSection, KeyType) != TypeApplication)
|
|
|
|
|
m_isValid = false;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_name = m_keyFile.getLocaleStr(MainSection, KeyName, "");
|
|
|
|
|
m_icon = m_keyFile.getStr(MainSection, KeyIcon);
|
|
|
|
|
m_id = getId();
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DesktopInfo::~DesktopInfo()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string DesktopInfo::getFileName()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_fileName;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DesktopInfo::isValidDesktop()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_isValid;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DesktopInfo::shouldShow()
|
|
|
|
|
{
|
|
|
|
|
if (getNoDisplay() || getIsHidden())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> desktopEnvs;
|
|
|
|
|
return getShowIn(desktopEnvs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DesktopInfo::getNoDisplay()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getBool(MainSection, KeyNoDisplay);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DesktopInfo::getIsHidden()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getBool(MainSection, KeyHidden);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DesktopInfo::getShowIn(std::vector<std::string> desktopEnvs)
|
|
|
|
|
{
|
|
|
|
|
if (desktopEnvs.size() == 0) {
|
|
|
|
|
if (currentDesktops.size() == 0) {
|
|
|
|
|
const char *env = getenv(envDesktopEnv.c_str());
|
|
|
|
|
const auto &desktop = DString::splitChars(env, ':');
|
|
|
|
|
currentDesktops.assign(desktop.begin(), desktop.end());
|
|
|
|
|
}
|
|
|
|
|
desktopEnvs.assign(currentDesktops.begin(), currentDesktops.end());
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
std::vector<std::string> onlyShowIn = m_keyFile.getStrList(MainSection, KeyOnlyShowIn);
|
|
|
|
|
std::vector<std::string> notShowIn = m_keyFile.getStrList(MainSection, KeyNotShowIn);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
|
|
for (const auto &desktop : desktopEnvs) {
|
|
|
|
|
bool ret = std::any_of(onlyShowIn.begin(), onlyShowIn.end(),
|
|
|
|
|
[&desktop](const auto &d) {return d == desktop;});
|
|
|
|
|
if (ret)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
ret = std::any_of(notShowIn.begin(), notShowIn.end(),
|
|
|
|
|
[&desktop](const auto &d) {return d == desktop;});
|
|
|
|
|
if (ret)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return onlyShowIn.size() == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string DesktopInfo::getExecutable()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getStr(MainSection, KeyExec);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DesktopInfo::isExecutableOk()
|
|
|
|
|
{
|
|
|
|
|
// 检查TryExec字段
|
|
|
|
|
std::string value = getTryExec();
|
|
|
|
|
std::vector<std::string> parts = DString::splitStr(value, ' ');
|
|
|
|
|
if (parts.size() > 0 ) {
|
|
|
|
|
value.assign(parts[0]);
|
|
|
|
|
DString::delQuote(value);
|
|
|
|
|
if (strstr(value.c_str(), "/") && DFile::isExisted(value))
|
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return findExecutable(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查Exec字段
|
|
|
|
|
value.assign(getExecutable());
|
|
|
|
|
parts.clear();
|
|
|
|
|
parts = DString::splitStr(value, ' ');
|
|
|
|
|
if (parts.size() > 0) {
|
|
|
|
|
value.assign(parts[0]);
|
|
|
|
|
DString::delQuote(value);
|
|
|
|
|
if (strstr(value.c_str(), "/") && DFile::isExisted(value))
|
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return findExecutable(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DesktopInfo::isInstalled()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
const char *name = m_fileName.c_str();
|
2022-04-24 14:52:13 +08:00
|
|
|
|
const char *found = strstr(name, "/applications/");
|
|
|
|
|
if (!found)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
auto appDirs = BaseDir::appDirs();
|
|
|
|
|
return std::any_of(appDirs.begin(), appDirs.end(),
|
2022-05-15 12:10:42 +08:00
|
|
|
|
[&name, &found] (std::string dir) -> bool {return strneq(dir.c_str(), name, size_t(found - name));});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// [Desktop Action new-window] or [Full_Screenshot Shortcut Group]
|
|
|
|
|
bool DesktopInfo::isDesktopAction(std::string name)
|
|
|
|
|
{
|
|
|
|
|
return DString::startWith(name.c_str(), "Desktop Action") || DString::endWith(name.c_str(), "Shortcut Group");
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<DesktopAction> DesktopInfo::getActions()
|
|
|
|
|
{
|
|
|
|
|
std::vector<DesktopAction> actions;
|
2022-05-15 12:10:42 +08:00
|
|
|
|
for (const auto &mainKey : m_keyFile.getMainKeys()) {
|
2022-04-24 14:52:13 +08:00
|
|
|
|
if (DString::startWith(mainKey, "Desktop Action")
|
|
|
|
|
|| DString::endWith(mainKey, "Shortcut Group")) {
|
|
|
|
|
DesktopAction action;
|
2022-05-15 12:10:42 +08:00
|
|
|
|
action.name = m_keyFile.getLocaleStr(mainKey, KeyName, "");
|
|
|
|
|
action.exec = m_keyFile.getStr(mainKey, KeyExec);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
actions.push_back(action);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return actions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 使用appId获取DesktopInfo需检查有效性
|
|
|
|
|
DesktopInfo DesktopInfo::getDesktopInfoById(std::string appId)
|
|
|
|
|
{
|
|
|
|
|
if (!DString::endWith(appId, ".desktop"))
|
|
|
|
|
appId += ".desktop";
|
|
|
|
|
|
|
|
|
|
for (const auto & dir : BaseDir::appDirs()) {
|
|
|
|
|
std::string filePath = dir + appId;
|
|
|
|
|
//检测文件有效性
|
|
|
|
|
if (DFile::isExisted(filePath)) {
|
|
|
|
|
return DesktopInfo(filePath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DesktopInfo("");
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
bool DesktopInfo::getTerminal()
|
|
|
|
|
{
|
|
|
|
|
return m_keyFile.getBool(MainSection, KeyTerminal);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 14:52:13 +08:00
|
|
|
|
// TryExec is Path to an executable file on disk used to determine if the program is actually installed
|
|
|
|
|
std::string DesktopInfo::getTryExec()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getStr(MainSection, KeyTryExec);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 按$PATH路径查找执行文件
|
|
|
|
|
bool DesktopInfo::findExecutable(std::string &exec)
|
|
|
|
|
{
|
|
|
|
|
static const char *path = getenv("PATH");
|
|
|
|
|
static std::vector<std::string> paths = DString::splitChars(path, ':');
|
|
|
|
|
return std::any_of(paths.begin(), paths.end(), [&exec](std::string path) {return DFile::isExisted(path + "/" +exec);});
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief DesktopInfo::getId
|
|
|
|
|
* filename must has suffix desktopExt
|
|
|
|
|
* example:
|
|
|
|
|
* /usr/share/applications/a.desktop -> a
|
|
|
|
|
* /usr/share/applications/kde4/a.desktop -> kde4/a
|
|
|
|
|
* /xxxx/dir/a.desktop -> /xxxx/dir/a
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
2022-04-24 14:52:13 +08:00
|
|
|
|
std::string DesktopInfo::getId()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
if (!m_id.empty())
|
|
|
|
|
return m_id;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
|
|
std::string idStr;
|
2022-05-15 12:10:42 +08:00
|
|
|
|
auto const suffixPos = m_fileName.find(".desktop");
|
2022-04-24 14:52:13 +08:00
|
|
|
|
if (suffixPos == std::string::npos)
|
|
|
|
|
return "";
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
idStr = m_fileName.substr(0, m_fileName.size() - 8); // trim suffix
|
2022-04-24 14:52:13 +08:00
|
|
|
|
size_t dirPos = idStr.find("/applications/");
|
|
|
|
|
if (dirPos == std::string::npos)
|
2022-05-27 21:03:41 +08:00
|
|
|
|
return idStr;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
|
|
std::string baseDir(idStr.substr(0, dirPos + 14)); // length of "/applications/" is 14
|
|
|
|
|
std::vector<std::string> appDirs = BaseDir::appDirs();
|
|
|
|
|
bool installed = std::any_of(appDirs.begin(), appDirs.end(),
|
|
|
|
|
[&baseDir](const auto &dir) {return dir == baseDir;});
|
|
|
|
|
|
|
|
|
|
if (installed) {
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_id = idStr.substr(baseDir.size(), idStr.size());
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_id;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string DesktopInfo::getGenericName()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getLocaleStr(MainSection, KeyGenericName, "");
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string DesktopInfo::getName()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_name;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string DesktopInfo::getIcon()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_icon;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string DesktopInfo::getCommandLine()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getStr(MainSection, KeyExec);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> DesktopInfo::getKeywords()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getLocaleStrList(MainSection, KeyKeywords, "");
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> DesktopInfo::getCategories()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_keyFile.getStrList(MainSection, KeyCategories);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DesktopInfo::setDesktopOverrideExec(const std::string &execStr)
|
|
|
|
|
{
|
|
|
|
|
m_overRideExec = execStr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KeyFile *DesktopInfo::getKeyFile()
|
|
|
|
|
{
|
|
|
|
|
return &m_keyFile;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// class AppsDir
|
|
|
|
|
AppsDir::AppsDir(const std::string &dirPath)
|
2022-05-15 12:10:42 +08:00
|
|
|
|
: m_path(dirPath)
|
2022-04-24 14:52:13 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AppsDir::~AppsDir()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string AppsDir::getPath()
|
|
|
|
|
{
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_path;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取目录对应的应用名称
|
|
|
|
|
std::map<std::string, bool> AppsDir::getAppNames()
|
|
|
|
|
{
|
|
|
|
|
DIR* dp;
|
|
|
|
|
struct dirent* ep;
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
dp = opendir(m_path.c_str());
|
|
|
|
|
if (!dp) {
|
|
|
|
|
std::cout << "Couldn't open directory " << m_path << std::endl;
|
|
|
|
|
return m_appNames;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((ep = readdir(dp))) {
|
|
|
|
|
if (ep->d_type != DT_REG && ep->d_type != DT_LNK)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!DString::endWith(ep->d_name, ".desktop"))
|
|
|
|
|
continue;
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
m_appNames.insert({ep->d_name, true});
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
closedir(dp);
|
|
|
|
|
|
2022-05-15 12:10:42 +08:00
|
|
|
|
return m_appNames;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取所有应用信息
|
|
|
|
|
std::vector<DesktopInfo> AppsDir::getAllDesktopInfos()
|
|
|
|
|
{
|
|
|
|
|
std::map<std::string, bool> recoder;
|
|
|
|
|
std::vector<DesktopInfo> desktopInfos;
|
|
|
|
|
|
|
|
|
|
for (auto dir : BaseDir::appDirs()) {
|
|
|
|
|
AppsDir appsDir(dir);
|
|
|
|
|
std::map<std::string, bool> appNames = appsDir.getAppNames();
|
|
|
|
|
if (appNames.size() == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (const auto &iter : appNames) {
|
|
|
|
|
if (recoder.find(iter.first) != recoder.end())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
std::string filePath = dir + iter.first;
|
|
|
|
|
DesktopInfo desktopInfo(filePath);
|
|
|
|
|
if (!desktopInfo.isValidDesktop())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!desktopInfo.shouldShow())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
desktopInfos.push_back(std::move(desktopInfo));
|
|
|
|
|
recoder[iter.first] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return desktopInfos;
|
|
|
|
|
}
|
|
|
|
|
|