Hyprland/src/config/ConfigManager.cpp

1524 lines
49 KiB
C++
Raw Normal View History

2022-03-17 15:53:45 +01:00
#include "ConfigManager.hpp"
2022-03-19 17:48:18 +01:00
#include "../managers/KeybindManager.hpp"
2022-03-17 15:53:45 +01:00
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <fstream>
#include <iostream>
CConfigManager::CConfigManager() {
setDefaultVars();
2022-07-28 13:28:43 +02:00
setDefaultAnimationVars();
std::string CONFIGPATH;
if (g_pCompositor->explicitConfigPath == "") {
static const char* const ENVHOME = getenv("HOME");
CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf");
} else {
CONFIGPATH = g_pCompositor->explicitConfigPath;
}
2022-05-16 10:09:20 +02:00
configPaths.emplace_back(CONFIGPATH);
2022-07-01 15:57:56 +02:00
Debug::disableLogs = &configValues["debug:disable_logs"].intValue;
2022-07-18 11:46:42 +02:00
Debug::disableTime = &configValues["debug:disable_time"].intValue;
}
void CConfigManager::setDefaultVars() {
configValues["general:max_fps"].intValue = 60;
configValues["general:sensitivity"].floatValue = 1.0f;
2022-06-22 13:01:59 +02:00
configValues["general:apply_sens_to_raw"].intValue = 0;
2022-03-20 19:58:12 +01:00
configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated
2022-03-17 15:53:45 +01:00
configValues["general:damage_tracking"].strValue = "full";
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_FULL;
2022-04-14 16:43:29 +02:00
2022-03-17 15:53:45 +01:00
configValues["general:border_size"].intValue = 1;
2022-06-21 22:54:41 +02:00
configValues["general:no_border_on_floating"].intValue = 0;
2022-03-17 15:53:45 +01:00
configValues["general:gaps_in"].intValue = 5;
configValues["general:gaps_out"].intValue = 20;
2022-03-19 16:13:19 +01:00
configValues["general:col.active_border"].intValue = 0xffffffff;
configValues["general:col.inactive_border"].intValue = 0xff444444;
2022-06-24 23:27:02 +02:00
configValues["general:cursor_inactive_timeout"].intValue = 0;
2022-08-01 18:50:16 +02:00
configValues["general:no_cursor_warps"].intValue = 0;
2022-07-16 15:57:31 +02:00
configValues["general:layout"].strValue = "dwindle";
2022-07-10 15:41:26 +02:00
configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0;
2022-07-12 15:41:28 +02:00
configValues["misc:no_vfr"].intValue = 1;
2022-07-30 22:26:46 +02:00
configValues["misc:damage_entire_on_snapshot"].intValue = 0;
2022-07-31 15:46:42 +02:00
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
2022-08-06 22:26:32 +02:00
configValues["misc:always_follow_on_dnd"].intValue = 1;
configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
2022-08-16 21:56:54 +02:00
configValues["misc:animate_manual_resizes"].intValue = 0;
2022-09-10 17:28:41 +02:00
configValues["misc:disable_autoreload"].intValue = 0;
2022-03-23 22:01:59 +01:00
configValues["debug:int"].intValue = 0;
2022-05-05 15:09:26 +02:00
configValues["debug:log_damage"].intValue = 0;
2022-05-28 17:32:19 +02:00
configValues["debug:overlay"].intValue = 0;
2022-06-29 11:44:00 +02:00
configValues["debug:damage_blink"].intValue = 0;
2022-07-01 15:57:56 +02:00
configValues["debug:disable_logs"].intValue = 0;
2022-07-18 11:46:42 +02:00
configValues["debug:disable_time"].intValue = 1;
2022-08-31 11:17:04 +02:00
configValues["decoration:rounding"].intValue = 0;
2022-04-09 16:51:08 +02:00
configValues["decoration:blur"].intValue = 1;
configValues["decoration:blur_size"].intValue = 8;
2022-04-09 17:06:09 +02:00
configValues["decoration:blur_passes"].intValue = 1;
2022-05-28 18:57:32 +02:00
configValues["decoration:blur_ignore_opacity"].intValue = 0;
2022-08-02 15:26:44 +02:00
configValues["decoration:blur_new_optimizations"].intValue = 0;
2022-04-17 21:44:06 +02:00
configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1;
2022-06-26 20:09:42 +02:00
configValues["decoration:multisample_edges"].intValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 0;
2022-06-25 20:28:40 +02:00
configValues["decoration:drop_shadow"].intValue = 1;
configValues["decoration:shadow_range"].intValue = 4;
configValues["decoration:shadow_render_power"].intValue = 3;
configValues["decoration:shadow_ignore_window"].intValue = 1;
2022-06-26 22:15:06 +02:00
configValues["decoration:shadow_offset"].strValue = "0 0";
2022-06-25 20:28:40 +02:00
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
2022-08-30 12:46:17 +02:00
configValues["decoration:dim_inactive"].intValue = 0;
configValues["decoration:dim_strength"].floatValue = 0.5f;
2022-04-05 15:50:47 +02:00
2022-04-02 20:04:32 +02:00
configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:col.group_border"].intValue = 0x66777700;
configValues["dwindle:col.group_border_active"].intValue = 0x66ffff00;
2022-05-08 15:36:17 +02:00
configValues["dwindle:force_split"].intValue = 0;
2022-05-16 17:27:55 +02:00
configValues["dwindle:preserve_split"].intValue = 0;
2022-06-03 19:03:33 +02:00
configValues["dwindle:special_scale_factor"].floatValue = 0.8f;
configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
2022-08-01 12:51:52 +02:00
configValues["dwindle:no_gaps_when_only"].intValue = 0;
2022-08-19 22:03:35 +02:00
configValues["dwindle:use_active_for_splits"].intValue = 1;
2022-04-02 20:04:32 +02:00
2022-07-16 15:57:31 +02:00
configValues["master:special_scale_factor"].floatValue = 0.8f;
configValues["master:new_is_master"].intValue = 1;
2022-07-16 23:24:42 +02:00
configValues["master:new_on_top"].intValue = 0;
2022-08-01 12:57:37 +02:00
configValues["master:no_gaps_when_only"].intValue = 0;
2022-07-16 15:57:31 +02:00
2022-03-23 22:01:59 +01:00
configValues["animations:enabled"].intValue = 1;
configValues["animations:speed"].floatValue = 7.f;
2022-04-23 21:47:16 +02:00
configValues["animations:curve"].strValue = "default";
2022-05-14 16:43:30 +02:00
configValues["animations:windows_style"].strValue = STRVAL_EMPTY;
2022-04-23 21:47:16 +02:00
configValues["animations:windows_curve"].strValue = "[[f]]";
2022-03-31 17:53:28 +02:00
configValues["animations:windows_speed"].floatValue = 0.f;
2022-03-23 22:01:59 +01:00
configValues["animations:windows"].intValue = 1;
2022-05-14 16:43:30 +02:00
configValues["animations:borders_style"].strValue = STRVAL_EMPTY;
2022-04-23 21:47:16 +02:00
configValues["animations:borders_curve"].strValue = "[[f]]";
2022-03-31 17:53:28 +02:00
configValues["animations:borders_speed"].floatValue = 0.f;
2022-03-23 22:01:59 +01:00
configValues["animations:borders"].intValue = 1;
2022-05-14 16:43:30 +02:00
configValues["animations:fadein_style"].strValue = STRVAL_EMPTY;
2022-04-23 21:47:16 +02:00
configValues["animations:fadein_curve"].strValue = "[[f]]";
2022-03-31 17:53:28 +02:00
configValues["animations:fadein_speed"].floatValue = 0.f;
2022-03-23 22:01:59 +01:00
configValues["animations:fadein"].intValue = 1;
2022-05-14 16:43:30 +02:00
configValues["animations:workspaces_style"].strValue = STRVAL_EMPTY;
2022-05-12 11:27:31 +02:00
configValues["animations:workspaces_curve"].strValue = "[[f]]";
configValues["animations:workspaces_speed"].floatValue = 0.f;
configValues["animations:workspaces"].intValue = 1;
2022-03-24 21:05:34 +01:00
configValues["input:sensitivity"].floatValue = 0.f;
2022-08-19 20:01:51 +02:00
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
configValues["input:kb_layout"].strValue = "us";
2022-05-06 14:30:35 +02:00
configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
configValues["input:kb_options"].strValue = STRVAL_EMPTY;
configValues["input:kb_rules"].strValue = STRVAL_EMPTY;
configValues["input:kb_model"].strValue = STRVAL_EMPTY;
2022-04-19 18:51:53 +02:00
configValues["input:repeat_rate"].intValue = 25;
configValues["input:repeat_delay"].intValue = 600;
2022-05-06 19:34:48 +02:00
configValues["input:natural_scroll"].intValue = 0;
2022-06-02 19:47:11 +02:00
configValues["input:numlock_by_default"].intValue = 0;
2022-06-06 12:08:33 +02:00
configValues["input:force_no_accel"].intValue = 0;
2022-08-22 18:22:26 +02:00
configValues["input:float_switch_override_focus"].intValue = 1;
configValues["input:touchpad:natural_scroll"].intValue = 0;
2022-04-19 18:51:53 +02:00
configValues["input:touchpad:disable_while_typing"].intValue = 1;
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
configValues["input:touchpad:middle_button_emulation"].intValue = 0;
configValues["input:touchpad:tap-to-click"].intValue = 1;
configValues["input:touchpad:drag_lock"].intValue = 0;
2022-07-26 14:50:21 +02:00
configValues["binds:pass_mouse_when_bound"].intValue = 1;
2022-07-26 23:34:03 +02:00
configValues["binds:scroll_event_delay"].intValue = 300;
configValues["binds:workspace_back_and_forth"].intValue = 0;
configValues["binds:allow_workspace_cycles"].intValue = 0;
2022-07-26 14:50:21 +02:00
2022-07-07 11:52:12 +02:00
configValues["gestures:workspace_swipe"].intValue = 0;
2022-07-19 18:35:24 +02:00
configValues["gestures:workspace_swipe_fingers"].intValue = 3;
2022-07-07 11:52:12 +02:00
configValues["gestures:workspace_swipe_distance"].intValue = 300;
configValues["gestures:workspace_swipe_invert"].intValue = 1;
configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30;
configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f;
2022-04-13 20:19:40 +02:00
configValues["input:follow_mouse"].intValue = 1;
configValues["autogenerated"].intValue = 0;
2022-03-17 17:08:54 +01:00
}
2022-03-17 15:53:45 +01:00
2022-06-30 21:26:00 +02:00
void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
auto& cfgValues = deviceConfigs[dev];
cfgValues["sensitivity"].floatValue = 0.f;
2022-08-19 20:01:51 +02:00
cfgValues["kb_file"].strValue = STRVAL_EMPTY;
2022-06-30 21:26:00 +02:00
cfgValues["kb_layout"].strValue = "us";
cfgValues["kb_variant"].strValue = STRVAL_EMPTY;
cfgValues["kb_options"].strValue = STRVAL_EMPTY;
cfgValues["kb_rules"].strValue = STRVAL_EMPTY;
cfgValues["kb_model"].strValue = STRVAL_EMPTY;
cfgValues["repeat_rate"].intValue = 25;
cfgValues["repeat_delay"].intValue = 600;
cfgValues["natural_scroll"].intValue = 0;
cfgValues["numlock_by_default"].intValue = 0;
cfgValues["disable_while_typing"].intValue = 1;
cfgValues["clickfinger_behavior"].intValue = 0;
cfgValues["middle_button_emulation"].intValue = 0;
cfgValues["tap-to-click"].intValue = 1;
cfgValues["drag_lock"].intValue = 0;
2022-06-30 21:26:00 +02:00
}
2022-07-28 13:28:43 +02:00
void CConfigManager::setDefaultAnimationVars() {
if (isFirstLaunch) {
INITANIMCFG("global");
INITANIMCFG("windows");
INITANIMCFG("fade");
INITANIMCFG("border");
INITANIMCFG("workspaces");
// windows
INITANIMCFG("windowsIn");
INITANIMCFG("windowsOut");
INITANIMCFG("windowsMove");
// fade
INITANIMCFG("fadeIn");
INITANIMCFG("fadeOut");
INITANIMCFG("fadeSwitch");
INITANIMCFG("fadeShadow");
2022-08-30 12:46:17 +02:00
INITANIMCFG("fadeDim");
2022-07-28 13:28:43 +02:00
// border
// workspaces
2022-08-26 11:26:23 +02:00
INITANIMCFG("specialWorkspace");
2022-07-28 13:28:43 +02:00
}
// init the values
animationConfig["global"] = {
false,
"default",
"",
8.f,
1,
&animationConfig["general"],
nullptr
};
CREATEANIMCFG("windows", "global");
CREATEANIMCFG("fade", "global");
CREATEANIMCFG("border", "global");
CREATEANIMCFG("workspaces", "global");
CREATEANIMCFG("windowsIn", "windows");
CREATEANIMCFG("windowsOut", "windows");
CREATEANIMCFG("windowsMove", "windows");
CREATEANIMCFG("fadeIn", "fade");
CREATEANIMCFG("fadeOut", "fade");
CREATEANIMCFG("fadeSwitch", "fade");
CREATEANIMCFG("fadeShadow", "fade");
2022-08-30 12:46:17 +02:00
CREATEANIMCFG("fadeDim", "fade");
2022-08-26 11:26:23 +02:00
CREATEANIMCFG("specialWorkspace", "workspaces");
2022-07-28 13:28:43 +02:00
}
2022-03-17 17:08:54 +01:00
void CConfigManager::init() {
2022-03-20 19:58:12 +01:00
2022-03-17 15:53:45 +01:00
loadConfigLoadVars();
2022-03-19 17:00:52 +01:00
const char* const ENVHOME = getenv("HOME");
const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf");
struct stat fileStat;
int err = stat(CONFIGPATH.c_str(), &fileStat);
if (err != 0) {
Debug::log(WARN, "Error at statting config, error %i", errno);
}
2022-05-16 10:09:20 +02:00
configModifyTimes[CONFIGPATH] = fileStat.st_mtime;
2022-03-19 17:00:52 +01:00
2022-03-17 15:53:45 +01:00
isFirstLaunch = false;
}
void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
if (configValues.find(COMMAND) == configValues.end()) {
if (COMMAND.find("device:") != 0 /* devices parsed later */) {
if (COMMAND[0] == '$') {
// register a dynamic var
Debug::log(LOG, "Registered dynamic var \"%s\" -> %s", COMMAND.c_str(), VALUE.c_str());
configDynamicVars[COMMAND.substr(1)] = VALUE;
} else {
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
}
2022-05-16 09:38:42 +02:00
2022-06-30 21:26:00 +02:00
return;
}
2022-03-17 15:53:45 +01:00
}
2022-06-30 21:26:00 +02:00
SConfigValue* CONFIGENTRY = nullptr;
if (COMMAND.find("device:") == 0) {
const auto DEVICE = COMMAND.substr(7).substr(0, COMMAND.find_last_of(':') - 7);
const auto CONFIGVAR = COMMAND.substr(COMMAND.find_last_of(':') + 1);
if (!deviceConfigExists(DEVICE))
setDeviceDefaultVars(DEVICE);
auto it = deviceConfigs.find(DEVICE);
if (it->second.find(CONFIGVAR) == it->second.end()) {
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
return;
}
CONFIGENTRY = &it->second.at(CONFIGVAR);
} else {
CONFIGENTRY = &configValues.at(COMMAND);
}
2022-04-18 13:25:27 +02:00
2022-06-30 21:38:06 +02:00
CONFIGENTRY->set = true;
2022-06-30 21:26:00 +02:00
if (CONFIGENTRY->intValue != -1) {
2022-03-17 15:53:45 +01:00
try {
if (VALUE.find("0x") == 0) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
2022-06-30 21:26:00 +02:00
CONFIGENTRY->intValue = stol(VALUEWITHOUTHEX, nullptr, 16);
2022-07-12 10:28:42 +02:00
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
CONFIGENTRY->intValue = 1;
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
CONFIGENTRY->intValue = 0;
}
else
2022-06-30 21:26:00 +02:00
CONFIGENTRY->intValue = stol(VALUE);
2022-03-17 15:53:45 +01:00
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
2022-06-30 21:26:00 +02:00
} else if (CONFIGENTRY->floatValue != -1) {
2022-03-17 15:53:45 +01:00
try {
2022-06-30 21:26:00 +02:00
CONFIGENTRY->floatValue = stof(VALUE);
2022-03-17 15:53:45 +01:00
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
2022-06-30 21:26:00 +02:00
} else if (CONFIGENTRY->strValue != "") {
2022-03-17 15:53:45 +01:00
try {
2022-06-30 21:26:00 +02:00
CONFIGENTRY->strValue = VALUE;
2022-03-17 15:53:45 +01:00
} 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.
2022-06-09 15:03:34 +02:00
std::string toExec = args;
if (g_pXWaylandManager->m_sWLRXWayland)
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + toExec;
else
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + toExec;
Debug::log(LOG, "Config executing %s", toExec.c_str());
2022-06-16 21:19:36 +02:00
2022-06-15 19:06:51 +02:00
int socket[2];
2022-06-16 21:19:36 +02:00
if (pipe(socket) != 0) {
Debug::log(LOG, "Unable to create pipe for fork");
}
2022-06-15 19:06:51 +02:00
2022-06-16 21:19:36 +02:00
pid_t child, grandchild;
2022-06-15 19:06:51 +02:00
child = fork();
2022-06-16 21:19:36 +02:00
if (child < 0) {
2022-06-15 19:06:51 +02:00
close(socket[0]);
close(socket[1]);
Debug::log(LOG, "Fail to create the first fork");
return;
}
2022-06-16 21:19:36 +02:00
if (child == 0) {
2022-06-15 19:06:51 +02:00
// run in child
grandchild = fork();
2022-06-16 21:19:36 +02:00
if (grandchild == 0) {
2022-06-15 19:06:51 +02:00
// run in grandchild
close(socket[0]);
close(socket[1]);
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
// exit grandchild
_exit(0);
}
close(socket[0]);
2022-06-16 21:19:36 +02:00
write(socket[1], &grandchild, sizeof(grandchild));
2022-06-15 19:06:51 +02:00
close(socket[1]);
// exit child
2022-03-17 15:53:45 +01:00
_exit(0);
}
2022-06-15 19:06:51 +02:00
// run in parent
close(socket[1]);
2022-06-16 21:19:36 +02:00
read(socket[0], &grandchild, sizeof(grandchild));
2022-06-15 19:06:51 +02:00
close(socket[0]);
// clear child and leave child to init
waitpid(child, NULL, 0);
2022-06-16 21:19:36 +02:00
if (child < 0) {
2022-06-15 19:06:51 +02:00
Debug::log(LOG, "Fail to create the second fork");
return;
}
2022-06-16 21:19:36 +02:00
Debug::log(LOG, "Process created with pid %d", grandchild);
2022-03-17 15:53:45 +01:00
}
2022-03-17 16:56:33 +01:00
void CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
// get the monitor config
SMonitorRule newrule;
std::string curitem = "";
std::string argZ = args;
auto nextItem = [&]() {
auto idx = argZ.find_first_of(',');
if (idx != std::string::npos) {
curitem = argZ.substr(0, idx);
argZ = argZ.substr(idx + 1);
} else {
curitem = argZ;
2022-03-19 17:00:52 +01:00
argZ = "";
2022-03-17 16:56:33 +01:00
}
};
nextItem();
newrule.name = curitem;
nextItem();
if (curitem == "disable" || curitem == "disabled" || curitem == "addreserved" || curitem == "transform") {
2022-04-27 17:46:07 +02:00
if (curitem == "disable" || curitem == "disabled")
newrule.disabled = true;
else if (curitem == "transform") {
nextItem();
wl_output_transform transform = (wl_output_transform)std::stoi(curitem);
// overwrite if exists
for (auto& r : m_dMonitorRules) {
if (r.name == newrule.name) {
r.transform = transform;
return;
}
}
return;
} else if (curitem == "addreserved") {
2022-04-27 17:46:07 +02:00
nextItem();
int top = std::stoi(curitem);
nextItem();
int bottom = std::stoi(curitem);
nextItem();
int left = std::stoi(curitem);
nextItem();
int right = std::stoi(curitem);
m_mAdditionalReservedAreas[newrule.name] = {top, bottom, left, right};
return; // this is not a rule, ignore
} else {
Debug::log(ERR, "ConfigManager parseMonitor, curitem bogus???");
return;
}
2022-04-17 10:19:46 +02:00
2022-08-03 17:19:32 +02:00
if (std::find_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }) != m_dMonitorRules.end())
m_dMonitorRules.erase(std::remove_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }));
2022-04-21 17:33:24 +02:00
2022-04-17 10:19:46 +02:00
m_dMonitorRules.push_back(newrule);
2022-04-17 10:21:54 +02:00
2022-04-17 10:19:46 +02:00
return;
}
2022-07-30 22:54:29 +02:00
if (curitem.find("pref") == 0) {
newrule.resolution = Vector2D();
} else {
newrule.resolution.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
newrule.resolution.y = stoi(curitem.substr(curitem.find_first_of('x') + 1, curitem.find_first_of('@')));
2022-03-19 21:46:29 +01:00
2022-07-30 22:54:29 +02:00
if (curitem.contains("@"))
newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1));
2022-08-03 21:06:51 +02:00
}
2022-03-17 16:56:33 +01:00
nextItem();
2022-08-04 11:10:26 +02:00
if (curitem.find("auto") == 0) {
newrule.offset = Vector2D(-1, -1);
} else {
newrule.offset.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
newrule.offset.y = stoi(curitem.substr(curitem.find_first_of('x') + 1));
2022-03-17 16:56:33 +01:00
2022-08-04 11:10:26 +02:00
if (newrule.offset.x < 0 || newrule.offset.y < 0) {
parseError = "invalid offset. Offset cannot be negative.";
newrule.offset = Vector2D();
}
2022-08-03 21:06:51 +02:00
}
2022-03-17 16:56:33 +01:00
nextItem();
newrule.scale = stof(curitem);
2022-08-03 21:06:51 +02:00
if (newrule.scale < 0.25f) {
parseError = "not a valid scale.";
newrule.scale = 1;
}
2022-04-21 22:15:42 +02:00
nextItem();
if (curitem != "") {
// warning for old cfg
Debug::log(ERR, "Error in parsing rule for %s, possibly old config!", newrule.name.c_str());
parseError = "Error in setting monitor rule. Are you using the old syntax? Confront the wiki.";
return;
}
2022-08-03 17:19:32 +02:00
if (std::find_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }) != m_dMonitorRules.end())
m_dMonitorRules.erase(std::remove_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }));
2022-04-21 17:33:24 +02:00
2022-03-17 16:56:33 +01:00
m_dMonitorRules.push_back(newrule);
}
2022-04-23 21:47:16 +02:00
void CConfigManager::handleBezier(const std::string& command, const std::string& args) {
std::string curitem = "";
std::string argZ = args;
auto nextItem = [&]() {
auto idx = argZ.find_first_of(',');
if (idx != std::string::npos) {
curitem = argZ.substr(0, idx);
argZ = argZ.substr(idx + 1);
} else {
curitem = argZ;
argZ = "";
}
};
nextItem();
std::string bezierName = curitem;
nextItem();
2022-08-09 18:15:37 +02:00
if (curitem == "")
parseError = "too few arguments";
2022-04-23 21:47:16 +02:00
float p1x = std::stof(curitem);
nextItem();
2022-08-09 18:15:37 +02:00
if (curitem == "")
parseError = "too few arguments";
2022-04-23 21:47:16 +02:00
float p1y = std::stof(curitem);
nextItem();
2022-08-09 18:15:37 +02:00
if (curitem == "")
parseError = "too few arguments";
2022-04-23 21:47:16 +02:00
float p2x = std::stof(curitem);
nextItem();
2022-08-09 18:15:37 +02:00
if (curitem == "")
parseError = "too few arguments";
2022-04-23 21:47:16 +02:00
float p2y = std::stof(curitem);
2022-08-09 18:15:37 +02:00
nextItem();
if (curitem != "")
parseError = "too many arguments";
2022-04-23 21:47:16 +02:00
g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
}
2022-07-28 13:28:43 +02:00
void CConfigManager::setAnimForChildren(SAnimationPropertyConfig *const ANIM) {
for (auto& [name, anim] : animationConfig) {
if (anim.pParentAnimation == ANIM && !anim.overriden) {
// if a child isnt overriden, set the values of the parent
anim.pValues = ANIM->pValues;
setAnimForChildren(&anim);
}
}
};
2022-05-14 15:56:01 +02:00
void CConfigManager::handleAnimation(const std::string& command, const std::string& args) {
std::string curitem = "";
std::string argZ = args;
auto nextItem = [&]() {
auto idx = argZ.find_first_of(',');
if (idx != std::string::npos) {
curitem = argZ.substr(0, idx);
argZ = argZ.substr(idx + 1);
} else {
curitem = argZ;
argZ = "";
}
};
nextItem();
// Master on/off
// anim name
const auto ANIMNAME = curitem;
2022-07-28 13:28:43 +02:00
const auto PANIM = animationConfig.find(ANIMNAME);
2022-05-14 15:56:01 +02:00
2022-07-28 13:28:43 +02:00
if (PANIM == animationConfig.end()) {
parseError = "no such animation";
2022-05-14 15:56:01 +02:00
return;
}
2022-07-28 13:28:43 +02:00
PANIM->second.overriden = true;
PANIM->second.pValues = &PANIM->second;
2022-05-14 15:56:01 +02:00
nextItem();
// on/off
2022-07-28 13:28:43 +02:00
PANIM->second.internalEnabled = curitem == "1";
2022-05-14 15:56:01 +02:00
2022-08-07 19:28:46 +02:00
if (curitem != "0" && curitem != "1") {
parseError = "invalid animation on/off state";
}
2022-05-14 15:56:01 +02:00
nextItem();
2022-07-28 13:28:43 +02:00
// speed
if (isNumber(curitem, true)) {
PANIM->second.internalSpeed = std::stof(curitem);
2022-08-07 19:28:46 +02:00
if (PANIM->second.internalSpeed <= 0) {
parseError = "invalid speed";
PANIM->second.internalSpeed = 1.f;
}
2022-07-28 13:28:43 +02:00
} else {
PANIM->second.internalSpeed = 10.f;
2022-08-07 19:28:46 +02:00
parseError = "invalid speed";
2022-07-28 13:28:43 +02:00
}
2022-05-14 15:56:01 +02:00
nextItem();
// curve
2022-07-28 13:28:43 +02:00
PANIM->second.internalBezier = curitem;
2022-05-14 16:43:30 +02:00
2022-08-07 19:28:46 +02:00
if (!g_pAnimationManager->bezierExists(curitem)) {
parseError = "no such bezier";
PANIM->second.internalBezier = "default";
}
2022-05-14 16:43:30 +02:00
nextItem();
// style
2022-07-28 13:28:43 +02:00
PANIM->second.internalStyle = curitem;
2022-08-07 19:28:46 +02:00
if (curitem != "") {
const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, curitem);
if (ERR != "")
parseError = ERR;
}
2022-07-28 13:28:43 +02:00
// now, check for children, recursively
setAnimForChildren(&PANIM->second);
2022-05-14 15:56:01 +02:00
}
2022-07-20 22:33:43 +02:00
void CConfigManager::handleBind(const std::string& command, const std::string& value) {
2022-03-19 17:48:18 +01:00
// example:
2022-07-20 22:33:43 +02:00
// bind[fl]=SUPER,G,exec,dmenu_run <args>
// flags
bool locked = false;
2022-07-20 22:45:06 +02:00
bool release = false;
2022-07-25 14:42:49 +02:00
bool repeat = false;
2022-07-20 22:33:43 +02:00
const auto ARGS = command.substr(4);
2022-07-20 22:45:06 +02:00
2022-07-20 22:33:43 +02:00
for (auto& arg : ARGS) {
if (arg == 'l') {
locked = true;
2022-07-20 22:45:06 +02:00
} else if (arg == 'r') {
release = true;
2022-07-25 14:42:49 +02:00
} else if (arg == 'e') {
repeat = true;
2022-07-20 22:33:43 +02:00
} else {
parseError = "bind: invalid flag";
return;
}
}
2022-03-19 17:48:18 +01:00
2022-07-26 17:04:26 +02:00
if (release && repeat) {
parseError = "flags r and e are mutually exclusive";
return;
}
2022-03-19 17:48:18 +01:00
auto valueCopy = value;
const auto MOD = g_pKeybindManager->stringToModMask(valueCopy.substr(0, valueCopy.find_first_of(",")));
2022-05-12 12:41:28 +02:00
const auto MODSTR = valueCopy.substr(0, valueCopy.find_first_of(","));
2022-03-19 17:48:18 +01:00
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto KEY = valueCopy.substr(0, valueCopy.find_first_of(","));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto HANDLER = valueCopy.substr(0, valueCopy.find_first_of(","));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto COMMAND = valueCopy;
2022-04-21 15:50:52 +02:00
const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(HANDLER);
if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) {
Debug::log(ERR, "Invalid dispatcher!");
parseError = "Invalid dispatcher, requested \"" + HANDLER + "\" does not exist";
return;
}
2022-05-12 12:41:28 +02:00
if (MOD == 0 && MODSTR != "") {
Debug::log(ERR, "Invalid mod!");
parseError = "Invalid mod, requested mod \"" + MODSTR + "\" is not a valid mod.";
return;
}
2022-08-21 17:01:32 +02:00
if (KEY == "exclam" || KEY == "asciicircum" || KEY == "at") { // just some
parseError = "Your config contains (probably) wrong keys. The SHIFT keysym behavior has changed after v0.10.3beta. Please consult the wiki (Advanced configuring -> binds)";
return;
}
2022-07-08 09:27:17 +02:00
if (KEY != "") {
if (isNumber(KEY) && std::stoi(KEY) > 9)
2022-07-25 14:42:49 +02:00
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat});
2022-07-08 09:27:17 +02:00
else
2022-07-25 14:42:49 +02:00
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat});
2022-07-08 09:27:17 +02:00
}
2022-03-19 17:48:18 +01:00
}
2022-04-21 17:06:43 +02:00
void CConfigManager::handleUnbind(const std::string& command, const std::string& value) {
auto valueCopy = value;
const auto MOD = g_pKeybindManager->stringToModMask(valueCopy.substr(0, valueCopy.find_first_of(",")));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto KEY = valueCopy;
g_pKeybindManager->removeKeybind(MOD, KEY);
}
2022-09-06 11:57:11 +02:00
bool windowRuleValid(const std::string& RULE) {
return !(RULE != "float"
2022-03-24 18:22:01 +01:00
&& RULE != "tile"
2022-04-22 14:37:38 +02:00
&& RULE.find("opacity") != 0
2022-03-24 18:22:01 +01:00
&& RULE.find("move") != 0
&& RULE.find("size") != 0
2022-04-02 20:04:32 +02:00
&& RULE.find("pseudo") != 0
2022-04-21 17:17:47 +02:00
&& RULE.find("monitor") != 0
2022-06-24 22:28:54 +02:00
&& RULE != "nofocus"
&& RULE != "noblur"
2022-07-16 16:27:17 +02:00
&& RULE != "center"
2022-08-02 00:08:31 +02:00
&& RULE != "opaque"
2022-08-27 13:01:55 +02:00
&& RULE != "forceinput"
2022-06-26 12:12:29 +02:00
&& RULE != "fullscreen"
2022-09-10 13:11:02 +02:00
&& RULE != "pin"
2022-05-15 14:18:31 +02:00
&& RULE.find("animation") != 0
2022-05-28 17:48:01 +02:00
&& RULE.find("rounding") != 0
2022-09-06 11:57:11 +02:00
&& RULE.find("workspace") != 0);
}
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
const auto RULE = value.substr(0, value.find_first_of(","));
const auto VALUE = value.substr(value.find_first_of(",") + 1);
// check rule and value
if (RULE == "" || VALUE == "") {
return;
}
// verify we support a rule
if (!windowRuleValid(RULE)) {
Debug::log(ERR, "Invalid rule found: %s", RULE.c_str());
parseError = "Invalid rule found: " + RULE;
return;
}
2022-03-24 18:22:01 +01:00
m_dWindowRules.push_back({RULE, VALUE});
2022-09-06 11:57:11 +02:00
}
void CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
const auto RULE = value.substr(0, value.find_first_of(","));
const auto VALUE = value.substr(value.find_first_of(",") + 1);
if (!windowRuleValid(RULE)) {
Debug::log(ERR, "Invalid rulev2 found: %s", RULE.c_str());
parseError = "Invalid rulev2 found: " + RULE;
return;
}
2022-03-24 18:22:01 +01:00
2022-09-06 11:57:11 +02:00
// now we estract shit from the value
SWindowRule rule;
rule.v2 = true;
rule.szRule = RULE;
rule.szValue = VALUE;
2022-09-06 11:57:11 +02:00
const auto TITLEPOS = VALUE.find("title:");
const auto CLASSPOS = VALUE.find("class:");
const auto X11POS = VALUE.find("xwayland:");
const auto FLOATPOS = VALUE.find("floating:");
2022-09-06 11:57:11 +02:00
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && X11POS == std::string::npos && FLOATPOS == std::string::npos) {
2022-09-06 11:57:11 +02:00
Debug::log(ERR, "Invalid rulev2 syntax: %s", VALUE.c_str());
parseError = "Invalid rulev2 syntax: " + VALUE;
return;
}
auto extract = [&](size_t pos) -> std::string {
std::string result;
result = VALUE.substr(pos);
size_t min = 999999;
if (TITLEPOS > pos && TITLEPOS < min) min = TITLEPOS;
if (CLASSPOS > pos && CLASSPOS < min) min = CLASSPOS;
if (X11POS > pos && X11POS < min) min = X11POS;
if (FLOATPOS > pos && FLOATPOS < min) min = FLOATPOS;
2022-09-06 11:57:11 +02:00
result = result.substr(0, min - pos);
if (result.back() == ',')
result.pop_back();
return result;
};
if (CLASSPOS != std::string::npos) {
rule.szClass = extract(CLASSPOS + 6);
}
if (TITLEPOS != std::string::npos) {
rule.szTitle = extract(TITLEPOS + 6);
}
if (X11POS != std::string::npos) {
rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
}
if (FLOATPOS != std::string::npos) {
rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
}
2022-09-06 11:57:11 +02:00
m_dWindowRules.push_back(rule);
2022-03-24 18:22:01 +01:00
}
2022-07-06 22:12:03 +02:00
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
2022-07-15 13:29:56 +02:00
if (value.find("remove,") == 0) {
const auto TOREMOVE = value.substr(7);
m_dBlurLSNamespaces.erase(std::remove(m_dBlurLSNamespaces.begin(), m_dBlurLSNamespaces.end(), TOREMOVE));
return;
}
2022-07-06 22:12:03 +02:00
m_dBlurLSNamespaces.emplace_back(value);
}
2022-03-20 16:01:47 +01:00
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
const auto DISPLAY = value.substr(0, value.find_first_of(','));
const auto WORKSPACE = value.substr(value.find_first_of(',') + 1);
2022-03-20 16:01:47 +01:00
for (auto& mr : m_dMonitorRules) {
if (mr.name == DISPLAY) {
mr.defaultWorkspace = WORKSPACE;
2022-03-20 16:01:47 +01:00
break;
}
}
}
2022-06-22 20:23:20 +02:00
void CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
if (submap == "reset")
m_szCurrentSubmap = "";
else
m_szCurrentSubmap = submap;
}
2022-05-16 10:09:20 +02:00
void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
2022-08-19 20:01:51 +02:00
if (rawpath.length() < 2) {
2022-07-06 15:05:23 +02:00
Debug::log(ERR, "source= path garbage");
2022-08-19 20:01:51 +02:00
parseError = "source path " + rawpath + " bogus!";
2022-07-06 15:05:23 +02:00
return;
}
2022-08-19 22:18:09 +02:00
auto value = absolutePath(rawpath, configCurrentPath);
2022-05-16 10:09:20 +02:00
if (!std::filesystem::exists(value)) {
Debug::log(ERR, "source= file doesnt exist");
parseError = "source file " + value + " doesn't exist!";
return;
}
configPaths.push_back(value);
struct stat fileStat;
int err = stat(value.c_str(), &fileStat);
if (err != 0) {
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", value.c_str(), err, strerror(err));
return;
}
configModifyTimes[value] = fileStat.st_mtime;
std::ifstream ifs;
ifs.open(value);
std::string line = "";
int linenum = 1;
if (ifs.is_open()) {
while (std::getline(ifs, line)) {
// Read line by line.
try {
configCurrentPath = value;
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) + " (" + configCurrentPath + "): Line parsing error.";
}
if (parseError != "" && parseError.find("Config error at line") != 0) {
parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError;
}
++linenum;
}
ifs.close();
}
}
2022-09-12 21:05:52 +02:00
void CConfigManager::handleBindWS(const std::string& command, const std::string& value) {
const auto WS = value.substr(0, value.find_first_of(','));
const auto MON = value.substr(value.find_first_of(',') + 1);
boundWorkspaces.push_back({WS, MON});
}
2022-04-21 16:56:27 +02:00
std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE, bool dynamic) {
if (dynamic) {
2022-04-21 16:56:27 +02:00
parseError = "";
currentCategory = "";
}
2022-04-21 16:56:27 +02:00
if (COMMAND == "exec") {
if (isFirstLaunch) {
firstExecRequests.push_back(VALUE);
} else {
handleRawExec(COMMAND, VALUE);
}
} else if (COMMAND == "exec-once") {
if (isFirstLaunch) {
firstExecRequests.push_back(VALUE);
}
}
2022-05-14 15:56:01 +02:00
else if (COMMAND == "monitor") handleMonitor(COMMAND, VALUE);
2022-07-20 22:33:43 +02:00
else if (COMMAND.find("bind") == 0) handleBind(COMMAND, VALUE);
2022-05-14 15:56:01 +02:00
else if (COMMAND == "unbind") handleUnbind(COMMAND, VALUE);
else if (COMMAND == "workspace") handleDefaultWorkspace(COMMAND, VALUE);
else if (COMMAND == "windowrule") handleWindowRule(COMMAND, VALUE);
2022-09-06 11:57:11 +02:00
else if (COMMAND == "windowrulev2") handleWindowRuleV2(COMMAND, VALUE);
2022-05-14 15:56:01 +02:00
else if (COMMAND == "bezier") handleBezier(COMMAND, VALUE);
else if (COMMAND == "animation") handleAnimation(COMMAND, VALUE);
2022-05-16 10:09:20 +02:00
else if (COMMAND == "source") handleSource(COMMAND, VALUE);
2022-06-22 20:23:20 +02:00
else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE);
2022-07-06 22:12:03 +02:00
else if (COMMAND == "blurls") handleBlurLS(COMMAND, VALUE);
2022-09-12 21:05:52 +02:00
else if (COMMAND == "wsbind") handleBindWS(COMMAND, VALUE);
2022-05-14 15:56:01 +02:00
else
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
2022-04-21 16:56:27 +02:00
if (dynamic) {
std::string retval = parseError;
parseError = "";
// invalidate layouts jic
2022-06-30 15:44:26 +02:00
for (auto& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
2022-05-26 21:23:13 +02:00
// Update window border colors
2022-07-12 13:40:55 +02:00
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
2022-05-26 21:23:13 +02:00
2022-04-21 16:56:27 +02:00
return retval;
}
return parseError;
}
2022-05-16 09:38:42 +02:00
void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equalsPlace) {
auto dollarPlace = line.find_first_of('$', equalsPlace);
while (dollarPlace != std::string::npos) {
const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1);
for (auto&[var, value] : configDynamicVars) {
if (STRAFTERDOLLAR.find(var) == 0) {
line.replace(dollarPlace, var.length() + 1, value);
break;
}
}
dollarPlace = line.find_first_of('$', dollarPlace + 1);
}
}
2022-03-17 15:53:45 +01:00
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.contains(" {")) {
2022-03-17 15:53:45 +01:00
auto cat = line.substr(0, line.find(" {"));
transform(cat.begin(), cat.end(), cat.begin(), ::tolower);
2022-08-20 18:47:48 +02:00
std::replace(cat.begin(), cat.end(), ' ', '-');
2022-04-19 18:42:26 +02:00
if (currentCategory.length() != 0) {
currentCategory.push_back(':');
currentCategory.append(cat);
}
else {
currentCategory = cat;
}
2022-03-17 15:53:45 +01:00
return;
}
if (line.contains("}") && currentCategory != "") {
2022-08-27 23:12:01 +02:00
const auto LASTSEP = currentCategory.find_last_of(':');
2022-08-28 10:25:48 +02:00
if (LASTSEP == std::string::npos || currentCategory.contains("device"))
2022-08-27 23:12:01 +02:00
currentCategory = "";
else
currentCategory = currentCategory.substr(0, LASTSEP);
2022-03-17 15:53:45 +01:00
return;
}
// And parse
// check if command
const auto EQUALSPLACE = line.find_first_of('=');
2022-05-16 09:38:42 +02:00
// apply vars
applyUserDefinedVars(line, EQUALSPLACE);
2022-03-17 15:53:45 +01:00
if (EQUALSPLACE == std::string::npos)
return;
2022-04-18 13:25:27 +02:00
const auto COMMAND = removeBeginEndSpacesTabs(line.substr(0, EQUALSPLACE));
const auto VALUE = removeBeginEndSpacesTabs(line.substr(EQUALSPLACE + 1));
//
2022-03-17 15:53:45 +01:00
2022-04-21 16:56:27 +02:00
parseKeyword(COMMAND, VALUE);
2022-03-17 15:53:45 +01:00
}
void CConfigManager::loadConfigLoadVars() {
Debug::log(LOG, "Reloading the config!");
parseError = ""; // reset the error
currentCategory = ""; // reset the category
// reset all vars before loading
setDefaultVars();
2022-03-17 16:56:33 +01:00
m_dMonitorRules.clear();
2022-03-24 18:22:01 +01:00
m_dWindowRules.clear();
g_pKeybindManager->clearKeybinds();
2022-04-23 21:47:16 +02:00
g_pAnimationManager->removeAllBeziers();
2022-04-27 17:46:07 +02:00
m_mAdditionalReservedAreas.clear();
2022-05-16 09:38:42 +02:00
configDynamicVars.clear();
2022-06-30 21:26:00 +02:00
deviceConfigs.clear();
2022-07-06 22:12:03 +02:00
m_dBlurLSNamespaces.clear();
2022-09-12 21:05:52 +02:00
boundWorkspaces.clear();
2022-07-28 13:28:43 +02:00
setDefaultAnimationVars(); // reset anims
2022-03-17 16:56:33 +01:00
2022-05-16 10:09:20 +02:00
// paths
configPaths.clear();
std::string CONFIGPATH;
2022-05-16 10:09:20 +02:00
static const char* const ENVHOME = getenv("HOME");
const std::string CONFIGPARENTPATH = ENVHOME + (std::string) "/.config/hypr/";
2022-03-17 15:53:45 +01:00
if (g_pCompositor->explicitConfigPath == "") {
CONFIGPATH = CONFIGPARENTPATH + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
} else {
CONFIGPATH = g_pCompositor->explicitConfigPath;
}
2022-05-16 10:09:20 +02:00
configPaths.push_back(CONFIGPATH);
2022-03-17 15:53:45 +01:00
std::ifstream ifs;
ifs.open(CONFIGPATH);
2022-03-17 15:53:45 +01:00
if (!ifs.good()) {
if(g_pCompositor->explicitConfigPath == "") {
Debug::log(WARN, "Config reading error. (No file? Attempting to generate, backing up old one if exists)");
try {
std::filesystem::rename(CONFIGPATH, CONFIGPATH + ".backup");
} catch(...) { /* Probably doesn't exist */}
2022-03-17 15:53:45 +01:00
try {
if (!std::filesystem::is_directory(CONFIGPARENTPATH))
std::filesystem::create_directories(CONFIGPARENTPATH);
}
catch (...) {
parseError = "Broken config file! (Could not create directory)";
return;
}
}
std::ofstream ofs;
ofs.open(CONFIGPATH, std::ios::trunc);
ofs << AUTOCONFIG;
ofs.close();
ifs.open(CONFIGPATH);
if (!ifs.good()) {
parseError = "Broken config file! (Could not open)";
return;
}
2022-03-17 15:53:45 +01:00
}
std::string line = "";
int linenum = 1;
if (ifs.is_open()) {
while (std::getline(ifs, line)) {
// Read line by line.
try {
2022-05-16 10:09:20 +02:00
configCurrentPath = "~/.config/hypr/hyprland.conf";
2022-03-17 15:53:45 +01:00
parseLine(line);
} catch (...) {
Debug::log(ERR, "Error reading line from config. Line:");
Debug::log(NONE, "%s", line.c_str());
2022-05-16 10:09:20 +02:00
parseError += "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): Line parsing error.";
2022-03-17 15:53:45 +01:00
}
if (parseError != "" && parseError.find("Config error at line") != 0) {
2022-05-16 10:09:20 +02:00
parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError;
2022-03-17 15:53:45 +01:00
}
++linenum;
}
ifs.close();
}
2022-06-30 15:44:26 +02:00
for (auto& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
2022-03-20 11:14:24 +01:00
2022-04-10 16:19:49 +02:00
// Update the keyboard layout to the cfg'd one if this is not the first launch
if (!isFirstLaunch) {
2022-04-10 16:19:49 +02:00
g_pInputManager->setKeyboardLayout();
g_pInputManager->setMouseConfigs();
}
2022-03-24 21:05:34 +01:00
2022-04-14 16:43:29 +02:00
// Calculate the internal vars
2022-03-20 11:14:24 +01:00
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue);
2022-04-14 16:43:29 +02:00
const auto DAMAGETRACKINGMODE = g_pHyprRenderer->damageTrackingModeFromStr(configValues["general:damage_tracking"].strValue);
if (DAMAGETRACKINGMODE != DAMAGE_TRACKING_INVALID)
configValues["general:damage_tracking_internal"].intValue = DAMAGETRACKINGMODE;
else {
parseError = "invalid value for general:damage_tracking, supported: full, monitor, none";
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE;
}
// parseError will be displayed next frame
if (parseError != "")
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
else if (configValues["autogenerated"].intValue == 1)
2022-08-16 15:59:18 +02:00
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + CONFIGPATH + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", CColor(255, 255, 70, 255));
else
g_pHyprError->destroy();
2022-04-19 19:01:23 +02:00
// Set the modes for all monitors as we configured them
// not on first launch because monitors might not exist yet
// and they'll be taken care of in the newMonitor event
2022-08-14 23:26:18 +02:00
// ignore if nomonitorreload is set
if (!isFirstLaunch && !m_bNoMonitorReload) {
2022-04-19 19:01:23 +02:00
m_bWantsMonitorReload = true;
2022-07-27 12:32:00 +02:00
// check
ensureDPMS();
2022-04-19 19:01:23 +02:00
}
2022-05-26 21:23:13 +02:00
// Update window border colors
2022-07-12 13:40:55 +02:00
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
2022-06-26 22:47:13 +02:00
2022-07-16 15:57:31 +02:00
// update layout
g_pLayoutManager->switchToLayout(configValues["general:layout"].strValue);
for (auto& m : g_pCompositor->m_vMonitors) {
2022-09-06 18:12:25 +02:00
// mark blur dirty
2022-08-01 13:12:50 +02:00
g_pHyprOpenGL->markBlurDirtyForMonitor(m.get());
2022-09-06 18:12:25 +02:00
// Force the compositor to fully re-render all monitors
m->forceFullFrames = 2;
}
2022-08-14 23:26:18 +02:00
// Reset no monitor reload
m_bNoMonitorReload = false;
2022-03-17 15:53:45 +01:00
}
void CConfigManager::tick() {
2022-05-16 10:09:20 +02:00
static const char* const ENVHOME = getenv("HOME");
2022-03-17 15:53:45 +01:00
2022-03-19 16:13:19 +01:00
const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf");
2022-03-17 15:53:45 +01:00
if (!std::filesystem::exists(CONFIGPATH)) {
2022-05-17 13:16:37 +02:00
Debug::log(ERR, "Config doesn't exist??");
return;
}
2022-05-16 10:09:20 +02:00
bool parse = false;
for (auto& cf : configPaths) {
struct stat fileStat;
int err = stat(cf.c_str(), &fileStat);
if (err != 0) {
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", cf.c_str(), err, strerror(err));
return;
}
// check if we need to reload cfg
if (fileStat.st_mtime != configModifyTimes[cf] || m_bForceReload) {
parse = true;
configModifyTimes[cf] = fileStat.st_mtime;
}
2022-03-17 15:53:45 +01:00
}
2022-05-16 10:09:20 +02:00
if (parse) {
2022-05-08 15:28:45 +02:00
m_bForceReload = false;
2022-05-16 10:09:20 +02:00
2022-03-17 15:53:45 +01:00
loadConfigLoadVars();
}
}
std::mutex configmtx;
2022-06-30 21:26:00 +02:00
SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) {
2022-03-17 15:53:45 +01:00
std::lock_guard<std::mutex> lg(configmtx);
SConfigValue copy = configValues[val];
return copy;
}
2022-06-30 21:26:00 +02:00
SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) {
std::lock_guard<std::mutex> lg(configmtx);
2022-08-20 18:47:48 +02:00
auto devcopy = dev;
std::replace(devcopy.begin(), devcopy.end(), ' ', '-');
const auto it = deviceConfigs.find(devcopy);
2022-06-30 21:26:00 +02:00
if (it == deviceConfigs.end()) {
2022-08-20 18:47:48 +02:00
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", devcopy.c_str());
2022-06-30 21:26:00 +02:00
return SConfigValue();
}
SConfigValue copy = it->second[val];
2022-06-30 21:38:06 +02:00
// fallback if not set explicitly
if (!copy.set) {
for (auto& cv : configValues) {
2022-07-28 21:38:30 +02:00
auto foundIt = cv.first.find(val);
if (foundIt == std::string::npos)
continue;
2022-08-20 18:47:48 +02:00
if (cv.first == "input:" + val || cv.first == "input:touchpad:" + cv.first) {
2022-06-30 21:38:06 +02:00
copy = cv.second;
}
}
}
2022-06-30 21:26:00 +02:00
return copy;
}
int CConfigManager::getInt(const std::string& v) {
2022-03-17 15:53:45 +01:00
return getConfigValueSafe(v).intValue;
}
2022-06-30 21:26:00 +02:00
float CConfigManager::getFloat(const std::string& v) {
2022-03-17 15:53:45 +01:00
return getConfigValueSafe(v).floatValue;
}
2022-06-30 21:26:00 +02:00
std::string CConfigManager::getString(const std::string& v) {
2022-05-06 14:30:35 +02:00
const auto VAL = getConfigValueSafe(v).strValue;
if (VAL == STRVAL_EMPTY)
return "";
return VAL;
2022-03-17 15:53:45 +01:00
}
2022-03-17 16:56:33 +01:00
2022-06-30 21:26:00 +02:00
int CConfigManager::getDeviceInt(const std::string& dev, const std::string& v) {
return getConfigValueSafeDevice(dev, v).intValue;
}
float CConfigManager::getDeviceFloat(const std::string& dev, const std::string& v) {
return getConfigValueSafeDevice(dev, v).floatValue;
}
std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v) {
const auto VAL = getConfigValueSafeDevice(dev, v).strValue;
if (VAL == STRVAL_EMPTY)
return "";
return VAL;
}
void CConfigManager::setInt(std::string v, int val) {
configValues[v].intValue = val;
}
void CConfigManager::setFloat(std::string v, float val) {
configValues[v].floatValue = val;
}
void CConfigManager::setString(std::string v, std::string val) {
configValues[v].strValue = val;
}
2022-03-17 16:56:33 +01:00
SMonitorRule CConfigManager::getMonitorRuleFor(std::string name) {
SMonitorRule* found = nullptr;
for (auto& r : m_dMonitorRules) {
if (r.name == name) {
found = &r;
break;
}
}
if (found)
return *found;
2022-03-19 17:00:52 +01:00
Debug::log(WARN, "No rule found for %s, trying to use the first.", name.c_str());
2022-03-17 16:56:33 +01:00
for (auto& r : m_dMonitorRules) {
if (r.name == "") {
found = &r;
break;
}
}
if (found)
return *found;
2022-03-19 17:00:52 +01:00
Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-1, -1), .scale = 1}; // 0, 0 is preferred and -1, -1 is auto
2022-03-24 18:22:01 +01:00
}
std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow))
return std::vector<SWindowRule>();
std::vector<SWindowRule> returns;
std::string title = g_pXWaylandManager->getTitle(pWindow);
std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow);
Debug::log(LOG, "Searching for matching rules for %s (title: %s)", appidclass.c_str(), title.c_str());
2022-03-24 18:22:01 +01:00
for (auto& rule : m_dWindowRules) {
// check if we have a matching rule
2022-09-06 11:57:11 +02:00
if (!rule.v2) {
try {
if (rule.szValue.find("title:") == 0) {
// we have a title rule.
std::regex RULECHECK(rule.szValue.substr(6));
2022-09-06 11:57:11 +02:00
if (!std::regex_search(title, RULECHECK))
continue;
} else {
std::regex classCheck(rule.szValue);
2022-03-24 18:22:01 +01:00
2022-09-06 11:57:11 +02:00
if (!std::regex_search(appidclass, classCheck))
continue;
}
} catch (...) {
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
continue;
}
} else {
try {
if (rule.szClass != "") {
std::regex RULECHECK(rule.szClass);
if (!std::regex_search(appidclass, RULECHECK))
continue;
}
if (rule.szTitle != "") {
std::regex RULECHECK(rule.szTitle);
if (!std::regex_search(title, RULECHECK))
continue;
}
if (rule.bX11 != -1) {
if (pWindow->m_bIsX11 != rule.bX11)
continue;
}
if (rule.bFloating != -1) {
if (pWindow->m_bIsFloating != rule.bFloating)
continue;
}
2022-09-06 11:57:11 +02:00
} catch (...) {
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
continue;
}
2022-03-24 18:22:01 +01:00
}
// applies. Read the rule and behave accordingly
Debug::log(LOG, "Window rule %s -> %s matched %x [%s]", rule.szRule.c_str(), rule.szValue.c_str(), pWindow, pWindow->m_szTitle.c_str());
returns.push_back(rule);
}
return returns;
2022-04-12 20:02:57 +02:00
}
void CConfigManager::dispatchExecOnce() {
if (firstExecDispatched || isFirstLaunch)
return;
firstExecDispatched = true;
for (auto& c : firstExecRequests) {
handleRawExec("", c);
}
firstExecRequests.clear(); // free some kb of memory :P
2022-07-21 20:30:48 +02:00
// set input, fixes some certain issues
g_pInputManager->setKeyboardLayout();
g_pInputManager->setMouseConfigs();
2022-07-22 12:37:44 +02:00
// set ws names again
for (auto& ws : g_pCompositor->m_vWorkspaces) {
wlr_ext_workspace_handle_v1_set_name(ws->m_pWlrHandle, ws->m_szName.c_str());
}
2022-04-19 19:01:23 +02:00
}
void CConfigManager::performMonitorReload() {
2022-06-30 23:55:28 +02:00
bool overAgain = false;
2022-08-03 17:29:05 +02:00
for (auto& m : g_pCompositor->m_vRealMonitors) {
2022-06-30 15:44:26 +02:00
auto rule = getMonitorRuleFor(m->szName);
2022-06-30 23:55:28 +02:00
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true;
break;
}
2022-09-08 14:11:32 +02:00
g_pHyprRenderer->arrangeLayersForMonitor(m->ID);
2022-04-19 19:01:23 +02:00
}
2022-06-30 23:55:28 +02:00
if (overAgain)
performMonitorReload();
2022-04-19 19:01:23 +02:00
m_bWantsMonitorReload = false;
2022-04-21 22:15:42 +02:00
}
2022-04-23 14:16:02 +02:00
SConfigValue* CConfigManager::getConfigValuePtr(std::string val) {
return &configValues[val];
}
2022-06-30 21:26:00 +02:00
2022-08-11 21:16:38 +02:00
SConfigValue* CConfigManager::getConfigValuePtrSafe(std::string val) {
const auto IT = configValues.find(val);
if (IT == configValues.end())
return nullptr;
return &(IT->second);
}
2022-06-30 21:26:00 +02:00
bool CConfigManager::deviceConfigExists(const std::string& dev) {
2022-08-20 18:47:48 +02:00
auto copy = dev;
std::replace(copy.begin(), copy.end(), ' ', '-');
const auto it = deviceConfigs.find(copy);
2022-06-30 21:26:00 +02:00
return it != deviceConfigs.end();
}
2022-07-06 22:12:03 +02:00
bool CConfigManager::shouldBlurLS(const std::string& ns) {
for (auto& bls : m_dBlurLSNamespaces) {
if (bls == ns) {
return true;
}
}
return false;
}
2022-07-27 12:32:00 +02:00
void CConfigManager::ensureDPMS() {
for (auto& rm : g_pCompositor->m_vRealMonitors) {
auto rule = getMonitorRuleFor(rm->szName);
if (rule.disabled == rm->m_bEnabled) {
2022-08-03 21:19:12 +02:00
rm->m_pThisWrap = &rm;
2022-07-27 12:32:00 +02:00
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
}
}
}
2022-07-28 13:28:43 +02:00
SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) {
return &animationConfig[name];
}
void CConfigManager::addParseError(const std::string& err) {
if (parseError == "")
parseError = err;
2022-08-19 20:01:51 +02:00
}
2022-09-12 21:05:52 +02:00
CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
for (auto&[ws, mon] : boundWorkspaces) {
const auto WSNAME = ws.find("name:") == 0 ? ws.substr(5) : ws;
if (WSNAME == wsname) {
return g_pCompositor->getMonitorFromString(mon);
}
}
return nullptr;
}