internal: move to libhyprlang for config handling

This commit is contained in:
Vaxry 2023-12-31 01:37:50 +01:00
parent ef0e051255
commit 39ad021c75
7 changed files with 150 additions and 211 deletions

View file

@ -65,6 +65,7 @@ target_link_libraries(hyprpaper
GLESv2 GLESv2
pthread pthread
magic magic
hyprlang
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${CMAKE_SOURCE_DIR}/wlr-layer-shell-unstable-v1-protocol.o ${CMAKE_SOURCE_DIR}/wlr-layer-shell-unstable-v1-protocol.o
${CMAKE_SOURCE_DIR}/xdg-shell-protocol.o ${CMAKE_SOURCE_DIR}/xdg-shell-protocol.o

View file

@ -27,14 +27,21 @@ The development files of these packages need to be installed on the system for `
- libglvnd-core - libglvnd-core
- libjpeg-turbo - libjpeg-turbo
- libwebp - libwebp
- hyprlang
Also `gcc-c++` and `ninja` needs to installed. Please note hyprpaper > 0.5.0 depends on [hyprlang](https://github.com/hyprwm/hyprlang) which is new
and might not be packaged for your distro yet. If that's the case, build and install it from source.
To install all of these in Fedora, run this command: To install all of these in Fedora, run this command:
``` ```
sudo dnf install wayland-devel wayland-protocols-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel gcc-c++ sudo dnf install wayland-devel wayland-protocols-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel gcc-c++
``` ```
On Arch:
```
sudo pacman -S ninja gcc wayland-protocols libjpeg-turbo libwebp pango cairo pkgconf cmake libglvnd wayland
```
On OpenSUSE: On OpenSUSE:
``` ```
sudo zypper install ninja gcc-c++ wayland-protocols-devel Mesa-libGLESv3-devel file-devel sudo zypper install ninja gcc-c++ wayland-protocols-devel Mesa-libGLESv3-devel file-devel

View file

@ -1,8 +1,8 @@
#include "Hyprpaper.hpp" #include "Hyprpaper.hpp"
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <sys/types.h>
#include <signal.h> #include <signal.h>
#include <sys/types.h>
CHyprpaper::CHyprpaper() = default; CHyprpaper::CHyprpaper() = default;
@ -18,6 +18,8 @@ void CHyprpaper::init() {
g_pConfigManager = std::make_unique<CConfigManager>(); g_pConfigManager = std::make_unique<CConfigManager>();
g_pIPCSocket = std::make_unique<CIPCSocket>(); g_pIPCSocket = std::make_unique<CIPCSocket>();
g_pConfigManager->parse();
m_sDisplay = (wl_display*)wl_display_connect(nullptr); m_sDisplay = (wl_display*)wl_display_connect(nullptr);
if (!m_sDisplay) { if (!m_sDisplay) {
@ -27,7 +29,7 @@ void CHyprpaper::init() {
preloadAllWallpapersFromConfig(); preloadAllWallpapersFromConfig();
if (m_bIPCEnabled) if (std::any_cast<int64_t>(g_pConfigManager->config->getConfigValue("ipc")))
g_pIPCSocket->initialize(); g_pIPCSocket->initialize();
// run // run
@ -129,7 +131,6 @@ void CHyprpaper::preloadAllWallpapersFromConfig() {
} else { } else {
m_mWallpaperTargets[wp].create(wp); m_mWallpaperTargets[wp].create(wp);
} }
} }
g_pConfigManager->m_dRequestedPreloads.clear(); g_pConfigManager->m_dRequestedPreloads.clear();
@ -450,6 +451,8 @@ SPoolBuffer* CHyprpaper::getPoolBuffer(SMonitor* pMonitor, CWallpaperTarget* pWa
} }
void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
static auto* const PRENDERSPLASH = reinterpret_cast<int64_t*>(g_pConfigManager->config->getConfigValuePtr("splash"));
static auto* const PSPLASHOFFSET = reinterpret_cast<float*>(g_pConfigManager->config->getConfigValuePtr("splash_offset"));
const auto PWALLPAPERTARGET = m_mMonitorActiveWallpaperTargets[pMonitor]; const auto PWALLPAPERTARGET = m_mMonitorActiveWallpaperTargets[pMonitor];
const auto CONTAIN = m_mMonitorWallpaperRenderData[pMonitor->name].contain; const auto CONTAIN = m_mMonitorWallpaperRenderData[pMonitor->name].contain;
@ -508,7 +511,7 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
cairo_paint(PCAIRO); cairo_paint(PCAIRO);
if (g_pHyprpaper->m_bRenderSplash && getenv("HYPRLAND_INSTANCE_SIGNATURE")) { if (*PRENDERSPLASH && getenv("HYPRLAND_INSTANCE_SIGNATURE")) {
auto SPLASH = execAndGet("hyprctl splash"); auto SPLASH = execAndGet("hyprctl splash");
SPLASH.pop_back(); SPLASH.pop_back();
@ -524,9 +527,9 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
cairo_text_extents_t textExtents; cairo_text_extents_t textExtents;
cairo_text_extents(PCAIRO, SPLASH.c_str(), &textExtents); cairo_text_extents(PCAIRO, SPLASH.c_str(), &textExtents);
cairo_move_to(PCAIRO, ((DIMENSIONS.x - textExtents.width * scale) / 2.0) / scale, ((DIMENSIONS.y * (100 - m_fSplashOffset)) / 100 - textExtents.height * scale) / scale); cairo_move_to(PCAIRO, ((DIMENSIONS.x - textExtents.width * scale) / 2.0) / scale, ((DIMENSIONS.y * (100 - *PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale);
Debug::log(LOG, "Splash font size: %d, pos: %.2f, %.2f", FONTSIZE, (DIMENSIONS.x - textExtents.width) / 2.0 / scale, ((DIMENSIONS.y * (100 - m_fSplashOffset)) / 100 - textExtents.height * scale) / scale); Debug::log(LOG, "Splash font size: %d, pos: %.2f, %.2f", FONTSIZE, (DIMENSIONS.x - textExtents.width) / 2.0 / scale, ((DIMENSIONS.y * (100 - *PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale);
cairo_show_text(PCAIRO, SPLASH.c_str()); cairo_show_text(PCAIRO, SPLASH.c_str());

View file

@ -1,13 +1,13 @@
#pragma once #pragma once
#include "defines.hpp"
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "render/WallpaperTarget.hpp" #include "defines.hpp"
#include "helpers/Monitor.hpp"
#include "events/Events.hpp" #include "events/Events.hpp"
#include "helpers/PoolBuffer.hpp"
#include "helpers/MiscFunctions.hpp" #include "helpers/MiscFunctions.hpp"
#include "helpers/Monitor.hpp"
#include "helpers/PoolBuffer.hpp"
#include "ipc/Socket.hpp" #include "ipc/Socket.hpp"
#include "render/WallpaperTarget.hpp"
#include <mutex> #include <mutex>
struct SWallpaperRenderData { struct SWallpaperRenderData {
@ -17,17 +17,17 @@ struct SWallpaperRenderData {
class CHyprpaper { class CHyprpaper {
public: public:
// important // important
wl_display* m_sDisplay; // assured wl_display* m_sDisplay; // assured
wl_compositor* m_sCompositor; // assured wl_compositor* m_sCompositor; // assured
wl_shm* m_sSHM; // assured wl_shm* m_sSHM; // assured
zwlr_layer_shell_v1* m_sLayerShell = nullptr; // expected zwlr_layer_shell_v1* m_sLayerShell = nullptr; // expected
wp_fractional_scale_manager_v1* m_sFractionalScale = nullptr; // will remain null if not bound wp_fractional_scale_manager_v1* m_sFractionalScale = nullptr; // will remain null if not bound
wp_viewporter* m_sViewporter = nullptr; // expected wp_viewporter* m_sViewporter = nullptr; // expected
// init the utility // init the utility
CHyprpaper(); CHyprpaper();
void init(); void init();
void tick(bool force); void tick(bool force);
std::unordered_map<std::string, CWallpaperTarget> m_mWallpaperTargets; std::unordered_map<std::string, CWallpaperTarget> m_mWallpaperTargets;
std::unordered_map<std::string, std::string> m_mMonitorActiveWallpapers; std::unordered_map<std::string, std::string> m_mMonitorActiveWallpapers;
@ -36,39 +36,36 @@ public:
std::vector<std::unique_ptr<SPoolBuffer>> m_vBuffers; std::vector<std::unique_ptr<SPoolBuffer>> m_vBuffers;
std::vector<std::unique_ptr<SMonitor>> m_vMonitors; std::vector<std::unique_ptr<SMonitor>> m_vMonitors;
bool m_bIPCEnabled = true;
bool m_bRenderSplash = false;
float m_fSplashOffset = 2;
std::string m_szExplicitConfigPath; std::string m_szExplicitConfigPath;
bool m_bNoFractionalScale = false; bool m_bNoFractionalScale = false;
void removeOldHyprpaperImages(); void removeOldHyprpaperImages();
void preloadAllWallpapersFromConfig(); void preloadAllWallpapersFromConfig();
void recheckAllMonitors(); void recheckAllMonitors();
void ensureMonitorHasActiveWallpaper(SMonitor*); void ensureMonitorHasActiveWallpaper(SMonitor*);
void createLSForMonitor(SMonitor*); void createLSForMonitor(SMonitor*);
void renderWallpaperForMonitor(SMonitor*); void renderWallpaperForMonitor(SMonitor*);
void createBuffer(SPoolBuffer*, int32_t, int32_t, uint32_t); void createBuffer(SPoolBuffer*, int32_t, int32_t, uint32_t);
void destroyBuffer(SPoolBuffer*); void destroyBuffer(SPoolBuffer*);
int createPoolFile(size_t, std::string&); int createPoolFile(size_t, std::string&);
bool setCloexec(const int&); bool setCloexec(const int&);
void clearWallpaperFromMonitor(const std::string&); void clearWallpaperFromMonitor(const std::string&);
SMonitor* getMonitorFromName(const std::string&); SMonitor* getMonitorFromName(const std::string&);
bool isPreloaded(const std::string&); bool isPreloaded(const std::string&);
void recheckMonitor(SMonitor*); void recheckMonitor(SMonitor*);
void ensurePoolBuffersPresent(); void ensurePoolBuffersPresent();
SPoolBuffer* getPoolBuffer(SMonitor*, CWallpaperTarget*); SPoolBuffer* getPoolBuffer(SMonitor*, CWallpaperTarget*);
void unloadWallpaper(const std::string&); void unloadWallpaper(const std::string&);
void createSeat(wl_seat*); void createSeat(wl_seat*);
bool lockSingleInstance(); // fails on multi-instance bool lockSingleInstance(); // fails on multi-instance
void unlockSingleInstance(); void unlockSingleInstance();
std::mutex m_mtTickMutex; std::mutex m_mtTickMutex;
SMonitor* m_pLastMonitor = nullptr;
SMonitor* m_pLastMonitor = nullptr;
private: private:
bool m_bShouldExit = false;
bool m_bShouldExit = false;
}; };
inline std::unique_ptr<CHyprpaper> g_pHyprpaper; inline std::unique_ptr<CHyprpaper> g_pHyprpaper;

View file

@ -1,135 +1,18 @@
#include "ConfigManager.hpp" #include "ConfigManager.hpp"
#include "../Hyprpaper.hpp" #include "../Hyprpaper.hpp"
CConfigManager::CConfigManager() { static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
// Initialize the configuration const std::string COMMAND = C;
// Read file from default location const std::string VALUE = V;
// or from an explicit location given by user Hyprlang::CParseResult result;
std::string configPath = getMainConfigPath();
std::ifstream ifs;
ifs.open(configPath);
if (!ifs.good()) {
Debug::log(WARN, "Config file `%s` couldn't be opened. Running without a config!", configPath.c_str());
return;
}
std::string line = "";
int linenum = 1;
if (ifs.is_open()) {
while (std::getline(ifs, line)) {
// Read line by line
try {
parseLine(line);
} catch (...) {
Debug::log(ERR, "Error reading line from config. Line:");
Debug::log(NONE, "%s", line.c_str());
parseError += "Config error at line " + std::to_string(linenum) + ": Line parsing error.";
}
if (!parseError.empty()) {
parseError = "Config error at line " + std::to_string(linenum) + ": " + parseError;
break;
}
++linenum;
}
ifs.close();
}
if (!parseError.empty()) {
Debug::log(WARN, "Config parse error: \n%s\n\nRunning and ignoring errors...\n", parseError.c_str());
return;
}
}
std::string CConfigManager::getMainConfigPath() {
if (!g_pHyprpaper->m_szExplicitConfigPath.empty())
return g_pHyprpaper->m_szExplicitConfigPath;
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
std::string configPath;
if (!xdgConfigHome)
configPath = getenv("HOME") + std::string("/.config");
else
configPath = xdgConfigHome;
return configPath + "/hypr/hyprpaper.conf";
}
std::string CConfigManager::removeBeginEndSpacesTabs(std::string str) {
while (str[0] == ' ' || str[0] == '\t') {
str = str.substr(1);
}
while (str.length() != 0 && (str[str.length() - 1] == ' ' || str[str.length() - 1] == '\t')) {
str = str.substr(0, str.length() - 1);
}
return str;
}
void CConfigManager::parseLine(std::string& line) {
// first check if its not a comment
const auto COMMENTSTART = line.find_first_of('#');
if (COMMENTSTART == 0)
return;
// now, cut the comment off
if (COMMENTSTART != std::string::npos)
line = line.substr(0, COMMENTSTART);
// Strip line
while (line[0] == ' ' || line[0] == '\t') {
line = line.substr(1);
}
// And parse
// check if command
const auto EQUALSPLACE = line.find_first_of('=');
if (EQUALSPLACE == std::string::npos)
return;
const auto COMMAND = removeBeginEndSpacesTabs(line.substr(0, EQUALSPLACE));
const auto VALUE = removeBeginEndSpacesTabs(line.substr(EQUALSPLACE + 1));
parseKeyword(COMMAND, VALUE);
}
void CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE) {
if (COMMAND == "wallpaper")
handleWallpaper(COMMAND, VALUE);
else if (COMMAND == "preload")
handlePreload(COMMAND, VALUE);
else if (COMMAND == "unload")
handleUnload(COMMAND, VALUE);
else if (COMMAND == "ipc")
g_pHyprpaper->m_bIPCEnabled = VALUE == "1" || VALUE == "yes" || VALUE == "on" || VALUE == "true";
else if (COMMAND == "splash")
g_pHyprpaper->m_bRenderSplash = VALUE == "1" || VALUE == "yes" || VALUE == "on" || VALUE == "true";
else if (COMMAND == "splash_offset") {
try {
g_pHyprpaper->m_fSplashOffset = std::clamp(std::stof(VALUE), 0.f, 100.f);
} catch (std::exception& e) {
parseError = "invalid splash_offset value " + VALUE;
}
} else
parseError = "unknown keyword " + COMMAND;
}
void CConfigManager::handleWallpaper(const std::string& COMMAND, const std::string& VALUE) {
if (VALUE.find_first_of(',') == std::string::npos) { if (VALUE.find_first_of(',') == std::string::npos) {
parseError = "wallpaper failed (syntax)"; result.setError("wallpaper failed (syntax)");
return; return result;
} }
auto MONITOR = VALUE.substr(0, VALUE.find_first_of(',')); auto MONITOR = VALUE.substr(0, VALUE.find_first_of(','));
auto WALLPAPER = trimPath(VALUE.substr(VALUE.find_first_of(',') + 1)); auto WALLPAPER = g_pConfigManager->trimPath(VALUE.substr(VALUE.find_first_of(',') + 1));
bool contain = false; bool contain = false;
@ -144,21 +27,25 @@ void CConfigManager::handleWallpaper(const std::string& COMMAND, const std::stri
} }
if (!std::filesystem::exists(WALLPAPER)) { if (!std::filesystem::exists(WALLPAPER)) {
parseError = "wallpaper failed (no such file)"; result.setError("wallpaper failed (no such file)");
return; return result;
} }
if (std::find(m_dRequestedPreloads.begin(), m_dRequestedPreloads.end(), WALLPAPER) == m_dRequestedPreloads.end() && !g_pHyprpaper->isPreloaded(WALLPAPER)) { if (std::find(g_pConfigManager->m_dRequestedPreloads.begin(), g_pConfigManager->m_dRequestedPreloads.end(), WALLPAPER) == g_pConfigManager->m_dRequestedPreloads.end() && !g_pHyprpaper->isPreloaded(WALLPAPER)) {
parseError = "wallpaper failed (not preloaded)"; result.setError("wallpaper failed (not preloaded)");
return; return result;
} }
g_pHyprpaper->clearWallpaperFromMonitor(MONITOR); g_pHyprpaper->clearWallpaperFromMonitor(MONITOR);
g_pHyprpaper->m_mMonitorActiveWallpapers[MONITOR] = WALLPAPER; g_pHyprpaper->m_mMonitorActiveWallpapers[MONITOR] = WALLPAPER;
g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].contain = contain; g_pHyprpaper->m_mMonitorWallpaperRenderData[MONITOR].contain = contain;
return result;
} }
void CConfigManager::handlePreload(const std::string& COMMAND, const std::string& VALUE) { static Hyprlang::CParseResult handlePreload(const char* C, const char* V) {
const std::string COMMAND = C;
const std::string VALUE = V;
auto WALLPAPER = VALUE; auto WALLPAPER = VALUE;
if (WALLPAPER[0] == '~') { if (WALLPAPER[0] == '~') {
@ -167,30 +54,19 @@ void CConfigManager::handlePreload(const std::string& COMMAND, const std::string
} }
if (!std::filesystem::exists(WALLPAPER)) { if (!std::filesystem::exists(WALLPAPER)) {
parseError = "preload failed (no such file)"; Hyprlang::CParseResult result;
return; result.setError((std::string{"no such file: "} + WALLPAPER).c_str());
return result;
} }
m_dRequestedPreloads.emplace_back(WALLPAPER); g_pConfigManager->m_dRequestedPreloads.emplace_back(WALLPAPER);
return Hyprlang::CParseResult{};
} }
void CConfigManager::handleUnload(const std::string& COMMAND, const std::string& VALUE) { static Hyprlang::CParseResult handleUnloadAll(const char* C, const char* V) {
auto WALLPAPER = VALUE; const std::string COMMAND = C;
const std::string VALUE = V;
if (VALUE == "all") {
handleUnloadAll(COMMAND, VALUE);
return;
}
if (WALLPAPER[0] == '~') {
static const char* const ENVHOME = getenv("HOME");
WALLPAPER = std::string(ENVHOME) + WALLPAPER.substr(1);
}
g_pHyprpaper->unloadWallpaper(WALLPAPER);
}
void CConfigManager::handleUnloadAll(const std::string& COMMAND, const std::string& VALUE) {
std::vector<std::string> toUnload; std::vector<std::string> toUnload;
for (auto& [name, target] : g_pHyprpaper->m_mWallpaperTargets) { for (auto& [name, target] : g_pHyprpaper->m_mWallpaperTargets) {
@ -211,6 +87,69 @@ void CConfigManager::handleUnloadAll(const std::string& COMMAND, const std::stri
for (auto& tu : toUnload) for (auto& tu : toUnload)
g_pHyprpaper->unloadWallpaper(tu); g_pHyprpaper->unloadWallpaper(tu);
return Hyprlang::CParseResult{};
}
static Hyprlang::CParseResult handleUnload(const char* C, const char* V) {
const std::string COMMAND = C;
const std::string VALUE = V;
auto WALLPAPER = VALUE;
if (VALUE == "all")
return handleUnloadAll(C, V);
if (WALLPAPER[0] == '~') {
static const char* const ENVHOME = getenv("HOME");
WALLPAPER = std::string(ENVHOME) + WALLPAPER.substr(1);
}
g_pHyprpaper->unloadWallpaper(WALLPAPER);
return Hyprlang::CParseResult{};
}
CConfigManager::CConfigManager() {
// Initialize the configuration
// Read file from default location
// or from an explicit location given by user
std::string configPath = getMainConfigPath();
config = std::make_unique<Hyprlang::CConfig>(configPath.c_str(), Hyprlang::SConfigOptions{});
config->addConfigValue("ipc", {1L});
config->addConfigValue("splash", {1L});
config->addConfigValue("splash_offset", {2.F});
config->registerHandler(&handleWallpaper, "wallpaper", {.allowFlags = false});
config->registerHandler(&handleUnload, "unload", {.allowFlags = false});
config->registerHandler(&handlePreload, "preload", {.allowFlags = false});
config->registerHandler(&handleUnloadAll, "unloadAll", {.allowFlags = false});
config->commence();
}
void CConfigManager::parse() {
const auto ERROR = config->parse();
if (ERROR.error)
std::cout << "Error in config: \n"
<< ERROR.getError() << "\n";
}
std::string CConfigManager::getMainConfigPath() {
if (!g_pHyprpaper->m_szExplicitConfigPath.empty())
return g_pHyprpaper->m_szExplicitConfigPath;
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
std::string configPath;
if (!xdgConfigHome)
configPath = getenv("HOME") + std::string("/.config");
else
configPath = xdgConfigHome;
return configPath + "/hypr/hyprpaper.conf";
} }
// trim from both ends // trim from both ends

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include <hyprlang.hpp>
class CIPCSocket; class CIPCSocket;
@ -7,23 +8,15 @@ class CConfigManager {
public: public:
// gets all the data from the config // gets all the data from the config
CConfigManager(); CConfigManager();
void parse();
std::deque<std::string> m_dRequestedPreloads; std::deque<std::string> m_dRequestedPreloads;
std::string getMainConfigPath(); std::string getMainConfigPath();
private:
std::string parseError;
void parseLine(std::string&);
std::string removeBeginEndSpacesTabs(std::string in);
void parseKeyword(const std::string&, const std::string&);
void handleWallpaper(const std::string&, const std::string&);
void handlePreload(const std::string&, const std::string&);
void handleUnload(const std::string&, const std::string&);
void handleUnloadAll(const std::string&, const std::string&);
std::string trimPath(std::string path); std::string trimPath(std::string path);
std::unique_ptr<Hyprlang::CConfig> config;
private:
friend class CIPCSocket; friend class CIPCSocket;
}; };

View file

@ -99,12 +99,11 @@ bool CIPCSocket::mainThreadParseRequest() {
// parse // parse
if (copy.find("wallpaper") == 0 || copy.find("preload") == 0 || copy.find("unload") == 0) { if (copy.find("wallpaper") == 0 || copy.find("preload") == 0 || copy.find("unload") == 0) {
g_pConfigManager->parseError = ""; // reset parse error
g_pConfigManager->parseKeyword(copy.substr(0, copy.find_first_of(' ')), copy.substr(copy.find_first_of(' ') + 1)); const auto RESULT = g_pConfigManager->config->parseDynamic(copy.substr(0, copy.find_first_of(' ')).c_str(), copy.substr(copy.find_first_of(' ') + 1).c_str());
if (!g_pConfigManager->parseError.empty()) { if (RESULT.error) {
m_szReply = g_pConfigManager->parseError; m_szReply = RESULT.getError();
m_bReplyReady = true; m_bReplyReady = true;
m_bRequestReady = false; m_bRequestReady = false;
return false; return false;