SNI: Honor XDG_DATA_DIRS as icon directory

Also don't crash in Utils::FindFileWithName when directory doesn't exist

Potential fix for https://github.com/scorpion-26/gBar/issues/25
This commit is contained in:
scorpion-26 2023-07-25 01:45:26 +02:00
parent 73b5335024
commit fe7b02b10c
2 changed files with 63 additions and 4 deletions

View file

@ -2,6 +2,7 @@
#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <filesystem>
#include "Log.h"
@ -84,8 +85,27 @@ namespace Utils
return buf;
}
static std::vector<std::string> Split(const std::string& str, char delim)
{
std::stringstream strstr(str);
std::string curElem;
std::vector<std::string> result;
while (std::getline(strstr, curElem, delim))
{
if (!curElem.empty())
{
result.emplace_back(curElem);
}
}
return result;
}
inline std::string FindFileWithName(const std::string& directory, const std::string& name, const std::string& extension)
{
if (!std::filesystem::exists(directory))
{
return "";
}
for (auto& path : std::filesystem::recursive_directory_iterator(directory))
{
if (path.is_directory())

View file

@ -15,6 +15,7 @@
#include <stb/stb_image.h>
#include <fstream>
#include <cstdio>
namespace SNI
{
@ -122,6 +123,35 @@ namespace SNI
}
else
{
auto findIconWithoutPath = [](const char* iconName) -> std::string
{
std::string iconPath;
const char* dataDirs = getenv("XDG_DATA_DIRS");
// Nothing defined, look in $XDG_DATA_DIRS/icons
// network-manager-applet does this e.g.
if (dataDirs)
{
for (auto& dataDir : Utils::Split(dataDirs, ':'))
{
LOG("SNI: Searching icon " << iconName << " in " << dataDir << "/icons");
std::string path = Utils::FindFileWithName(dataDir + "/icons", iconName, ".png");
if (path != "")
{
iconPath = path;
break;
}
}
}
if (iconPath == "")
{
// Fallback to /usr/share/icons
LOG("SNI: Searching icon " << iconName << " in "
<< "/usr/share/icons");
iconPath = Utils::FindFileWithName("/usr/share/icons", iconName, ".png");
}
return iconPath;
};
// Get icon theme path
GVariant* themePathVariant = getProperty("IconThemePath"); // Not defined by freedesktop, I think ayatana does this...
GVariant* iconNameVariant = getProperty("IconName");
@ -139,9 +169,7 @@ namespace SNI
const char* iconName = g_variant_get_string(iconNameStr, nullptr);
if (strlen(themePath) == 0)
{
// Nothing defined, look in /usr/share/icons
// network-manager-applet does this
iconPath = Utils::FindFileWithName("/usr/share/icons", iconName, ".png");
iconPath = findIconWithoutPath(iconName);
}
else
{
@ -159,7 +187,12 @@ namespace SNI
g_variant_get(iconNameVariant, "(v)", &iconNameStr);
const char* iconName = g_variant_get_string(iconNameStr, nullptr);
iconPath = std::string(iconName);
iconPath = findIconWithoutPath(iconName);
if (iconPath == "")
{
// Try our luck with just using iconName, maybe its just an absolute path
iconPath = iconName;
}
g_variant_unref(iconNameVariant);
g_variant_unref(iconNameStr);
@ -170,6 +203,12 @@ namespace SNI
return item;
}
if (iconPath == "")
{
LOG("SNI: Cannot find icon path for " << name);
return item;
}
int width, height, channels;
stbi_uc* pixels = stbi_load(iconPath.c_str(), &width, &height, &channels, STBI_rgb_alpha);
if (!pixels)