2025-10-14 20:35:03 +03:00
|
|
|
#include "IconRegistry.hpp"
|
|
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <ranges>
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
2025-10-15 01:05:50 +03:00
|
|
|
#include <mini/ini.h>
|
|
|
|
|
|
2025-10-14 20:35:03 +03:00
|
|
|
IconTheme::IconTheme(std::filesystem::path const &themes_directory_path)
|
|
|
|
|
{
|
|
|
|
|
for (auto const &dir :
|
|
|
|
|
std::filesystem::directory_iterator(themes_directory_path)) {
|
|
|
|
|
if (!dir.is_directory())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto const index_path = dir.path() / "index.theme";
|
|
|
|
|
if (std::filesystem::is_regular_file(index_path))
|
|
|
|
|
continue;
|
2025-10-15 01:05:50 +03:00
|
|
|
|
|
|
|
|
mINI::INIFile ini_file(index_path);
|
|
|
|
|
mINI::INIStructure ini;
|
|
|
|
|
ini_file.read(ini);
|
|
|
|
|
|
|
|
|
|
auto const &directories { ini["Icon Theme"]["Directories"] };
|
|
|
|
|
for (auto const &&dir_entry : directories | std::views::split(':')) {
|
|
|
|
|
auto const dir_entry_str { std::string(
|
|
|
|
|
dir_entry.begin(), dir_entry.end()) };
|
|
|
|
|
auto const path { std::filesystem::path(dir_entry_str) };
|
|
|
|
|
auto const path_actual { dir.path() / path };
|
|
|
|
|
|
|
|
|
|
if (!std::filesystem::is_directory(path_actual))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto const &type_raw { ini[dir_entry_str]["Type"] };
|
|
|
|
|
DirectoryEntry::Type type;
|
|
|
|
|
if (type_raw == "Fixed") {
|
|
|
|
|
type = DirectoryEntry::Type::Fixed;
|
|
|
|
|
} else if (type_raw == "Scalable") {
|
|
|
|
|
type = DirectoryEntry::Type::Scalable;
|
|
|
|
|
} else if (type_raw == "Threshold") {
|
|
|
|
|
type = DirectoryEntry::Type::Threshold;
|
|
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto const &context_raw { ini[dir_entry_str]["context"] };
|
|
|
|
|
DirectoryEntry::Context context;
|
|
|
|
|
if (context_raw == "Actions") {
|
|
|
|
|
context = DirectoryEntry::Context::Actions;
|
|
|
|
|
} else if (type_raw == "Devices") {
|
|
|
|
|
context = DirectoryEntry::Context::Devices;
|
|
|
|
|
} else if (type_raw == "FileSystems") {
|
|
|
|
|
context = DirectoryEntry::Context::FileSystems;
|
|
|
|
|
} else if (type_raw == "MomeTypes") {
|
|
|
|
|
context = DirectoryEntry::Context::MimeTypes;
|
|
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int size { std::atoi(ini[dir_entry_str]["Size"].c_str()) };
|
|
|
|
|
|
|
|
|
|
m_directories.push_back({
|
|
|
|
|
.path = path,
|
|
|
|
|
.size = size,
|
|
|
|
|
.type = type,
|
|
|
|
|
.context = context,
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-10-14 20:35:03 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IconRegistry::IconRegistry()
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::filesystem::path> theme_directory_paths;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto const *env { getenv("HOME") };
|
|
|
|
|
if (env && *env) {
|
|
|
|
|
theme_directory_paths.push_back(
|
|
|
|
|
std::filesystem::path(env) / ".icons");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto const *env { getenv("XDG_DATA_DIRS") };
|
|
|
|
|
if (env && *env) {
|
|
|
|
|
theme_directory_paths.push_back(
|
|
|
|
|
std::filesystem::path(env) / "icons");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::filesystem::path const path { "/usr/share/pixmaps" };
|
|
|
|
|
if (std::filesystem::exists(path))
|
|
|
|
|
theme_directory_paths.push_back(path);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-15 01:05:50 +03:00
|
|
|
for (auto &&path : std::move(theme_directory_paths)
|
2025-10-14 20:35:03 +03:00
|
|
|
| std::views::filter([](std::filesystem::path &path) {
|
|
|
|
|
return std::filesystem::is_directory(path);
|
|
|
|
|
})) {
|
|
|
|
|
try {
|
|
|
|
|
m_themes.push_back({ path });
|
|
|
|
|
} catch (...) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_themes.empty()) {
|
|
|
|
|
throw std::runtime_error("Could not find any icon themes.");
|
|
|
|
|
}
|
|
|
|
|
}
|