Hyprland/src/config/ConfigManager.cpp

202 lines
5.9 KiB
C++
Raw Normal View History

2022-03-17 15:53:45 +01:00
#include "ConfigManager.hpp"
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <fstream>
#include <iostream>
CConfigManager::CConfigManager() {
configValues["general:max_fps"].intValue = 240;
configValues["general:border_size"].intValue = 1;
configValues["general:gaps_in"].intValue = 5;
configValues["general:gaps_out"].intValue = 20;
loadConfigLoadVars();
isFirstLaunch = false;
}
void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
if (configValues.find(COMMAND) == configValues.end()) {
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
return;
}
auto& CONFIGENTRY = configValues.at(COMMAND);
if (CONFIGENTRY.intValue != -1) {
try {
if (VALUE.find("0x") == 0) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
CONFIGENTRY.intValue = stol(VALUEWITHOUTHEX, nullptr, 16);
} else
CONFIGENTRY.intValue = stol(VALUE);
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
} else if (CONFIGENTRY.floatValue != -1) {
try {
CONFIGENTRY.floatValue = stof(VALUE);
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
} else if (CONFIGENTRY.strValue != "") {
try {
CONFIGENTRY.strValue = VALUE;
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
}
}
void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
// Exec in the background dont wait for it.
if (fork() == 0) {
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
_exit(0);
}
}
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);
// remove shit at the beginning
while (line[0] == ' ' || line[0] == '\t') {
line = line.substr(1);
}
if (line.find(" {") != std::string::npos) {
auto cat = line.substr(0, line.find(" {"));
transform(cat.begin(), cat.end(), cat.begin(), ::tolower);
currentCategory = cat;
return;
}
if (line.find("}") != std::string::npos && currentCategory != "") {
currentCategory = "";
return;
}
// And parse
// check if command
const auto EQUALSPLACE = line.find_first_of('=');
if (EQUALSPLACE == std::string::npos)
return;
const auto COMMAND = line.substr(0, EQUALSPLACE);
const auto VALUE = line.substr(EQUALSPLACE + 1);
if (COMMAND == "exec") {
handleRawExec(COMMAND, VALUE);
return;
} else if (COMMAND == "exec-once") {
if (isFirstLaunch) {
handleRawExec(COMMAND, VALUE);
return;
}
}
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
}
void CConfigManager::loadConfigLoadVars() {
Debug::log(LOG, "Reloading the config!");
parseError = ""; // reset the error
currentCategory = ""; // reset the category
const char* const ENVHOME = getenv("HOME");
const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf");
std::ifstream ifs;
ifs.open(CONFIGPATH.c_str());
if (!ifs.good()) {
Debug::log(WARN, "Config reading error. (No file?)");
parseError = "The config could not be read. (No file?)";
ifs.close();
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 != "" && parseError.find("Config error at line") != 0) {
parseError = "Config error at line " + std::to_string(linenum) + ": " + parseError;
}
++linenum;
}
ifs.close();
}
}
void CConfigManager::tick() {
const char* const ENVHOME = getenv("HOME");
const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprd.conf" : (std::string) "/.config/hypr/hypr.conf");
struct stat fileStat;
int err = stat(CONFIGPATH.c_str(), &fileStat);
if (err != 0) {
Debug::log(WARN, "Error at ticking config, error %i", errno);
}
// check if we need to reload cfg
if (fileStat.st_mtime != lastModifyTime) {
lastModifyTime = fileStat.st_mtime;
loadConfigLoadVars();
}
}
std::mutex configmtx;
SConfigValue CConfigManager::getConfigValueSafe(std::string val) {
std::lock_guard<std::mutex> lg(configmtx);
SConfigValue copy = configValues[val];
return copy;
}
int CConfigManager::getInt(std::string v) {
return getConfigValueSafe(v).intValue;
}
float CConfigManager::getFloat(std::string v) {
return getConfigValueSafe(v).floatValue;
}
std::string CConfigManager::getString(std::string v) {
return getConfigValueSafe(v).strValue;
}