Hyprland/src/config/ConfigManager.cpp

1981 lines
70 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>
extern "C" char** environ;
2022-03-17 15:53:45 +01:00
CConfigManager::CConfigManager() {
configValues["general:col.active_border"].data = std::make_shared<CGradientValueData>(0xffffffff);
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
2023-02-19 22:07:32 +01:00
configValues["general:col.group_border"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["general:col.group_border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
2022-11-26 18:56:43 +01:00
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;
2023-03-05 15:54:26 +01:00
populateEnvironment();
}
void CConfigManager::populateEnvironment() {
environmentVariables.clear();
for (char** env = environ; *env; ++env) {
const std::string ENVVAR = *env;
const auto VARIABLE = ENVVAR.substr(0, ENVVAR.find_first_of('='));
const auto VALUE = ENVVAR.substr(ENVVAR.find_first_of('=') + 1);
environmentVariables.emplace_back(std::make_pair<>(VARIABLE, VALUE));
2023-03-05 15:54:26 +01:00
}
std::sort(environmentVariables.begin(), environmentVariables.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
}
void CConfigManager::setDefaultVars() {
2023-02-27 00:14:19 +01:00
configValues["general:max_fps"].intValue = 60;
configValues["general:sensitivity"].floatValue = 1.0f;
configValues["general:apply_sens_to_raw"].intValue = 0;
configValues["general:border_size"].intValue = 1;
2022-06-21 22:54:41 +02:00
configValues["general:no_border_on_floating"].intValue = 0;
configValues["general:gaps_in"].intValue = 5;
configValues["general:gaps_out"].intValue = 20;
2022-11-26 18:56:43 +01:00
((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
2023-02-19 22:07:32 +01:00
((CGradientValueData*)configValues["general:col.group_border"].data.get())->reset(0x66777700);
((CGradientValueData*)configValues["general:col.group_border_active"].data.get())->reset(0x66ffff00);
2022-06-24 23:27:02 +02:00
configValues["general:cursor_inactive_timeout"].intValue = 0;
configValues["general:no_cursor_warps"].intValue = 0;
configValues["general:no_focus_fallback"].intValue = 0;
2023-02-18 23:35:31 +01:00
configValues["general:resize_on_border"].intValue = 0;
configValues["general:extend_border_grab_area"].intValue = 15;
configValues["general:hover_icon_on_border"].intValue = 1;
2023-02-27 00:14:19 +01:00
configValues["general:layout"].strValue = "dwindle";
2022-09-25 20:07:48 +02:00
configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0;
configValues["misc:vfr"].intValue = 1;
configValues["misc:vrr"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
2023-03-12 14:46:38 +01:00
configValues["misc:key_press_enables_dpms"].intValue = 0;
configValues["misc:always_follow_on_dnd"].intValue = 1;
configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
configValues["misc:animate_manual_resizes"].intValue = 0;
configValues["misc:animate_mouse_windowdragging"].intValue = 0;
configValues["misc:disable_autoreload"].intValue = 0;
configValues["misc:enable_swallow"].intValue = 0;
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
configValues["misc:swallow_exception_regex"].strValue = STRVAL_EMPTY;
configValues["misc:focus_on_activate"].intValue = 0;
configValues["misc:no_direct_scanout"].intValue = 1;
configValues["misc:hide_cursor_on_touch"].intValue = 1;
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
configValues["misc:suppress_portal_warnings"].intValue = 0;
configValues["misc:render_ahead_of_time"].intValue = 0;
configValues["misc:render_ahead_safezone"].intValue = 1;
2023-04-16 15:48:38 +02:00
configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
configValues["misc:cursor_zoom_rigid"].intValue = 0;
2023-03-24 20:37:37 +01:00
configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0;
configValues["debug:overlay"].intValue = 0;
configValues["debug:damage_blink"].intValue = 0;
configValues["debug:disable_logs"].intValue = 0;
configValues["debug:disable_time"].intValue = 1;
configValues["debug:enable_stdout_logs"].intValue = 0;
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
2023-04-04 15:49:58 +02:00
configValues["debug:manual_crash"].intValue = 0;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur"].intValue = 1;
configValues["decoration:blur_size"].intValue = 8;
configValues["decoration:blur_passes"].intValue = 1;
configValues["decoration:blur_ignore_opacity"].intValue = 0;
2022-11-23 16:41:12 +01:00
configValues["decoration:blur_new_optimizations"].intValue = 1;
configValues["decoration:blur_xray"].intValue = 0;
configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1;
configValues["decoration:multisample_edges"].intValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 0;
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;
configValues["decoration:shadow_offset"].vecValue = Vector2D();
configValues["decoration:shadow_scale"].floatValue = 1.f;
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
configValues["decoration:dim_inactive"].intValue = 0;
configValues["decoration:dim_strength"].floatValue = 0.5f;
2022-12-28 15:18:23 +01:00
configValues["decoration:dim_special"].floatValue = 0.2f;
2022-12-28 15:39:17 +01:00
configValues["decoration:dim_around"].floatValue = 0.4f;
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:force_split"].intValue = 0;
configValues["dwindle:preserve_split"].intValue = 0;
configValues["dwindle:special_scale_factor"].floatValue = 0.8f;
configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
configValues["dwindle:no_gaps_when_only"].intValue = 0;
configValues["dwindle:use_active_for_splits"].intValue = 1;
2023-03-07 15:24:04 +01:00
configValues["dwindle:default_split_ratio"].floatValue = 1.f;
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:mfact"].floatValue = 0.55f;
configValues["master:new_is_master"].intValue = 1;
configValues["master:always_center_master"].intValue = 0;
configValues["master:new_on_top"].intValue = 0;
configValues["master:no_gaps_when_only"].intValue = 0;
configValues["master:orientation"].strValue = "left";
configValues["master:inherit_fullscreen"].intValue = 1;
2023-04-13 16:20:58 +02:00
configValues["master:allow_small_split"].intValue = 0;
2023-02-27 00:14:19 +01:00
configValues["animations:enabled"].intValue = 1;
2023-02-27 00:14:19 +01:00
configValues["input:follow_mouse"].intValue = 1;
configValues["input:sensitivity"].floatValue = 0.f;
configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
configValues["input:kb_layout"].strValue = "us";
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;
configValues["input:repeat_rate"].intValue = 25;
configValues["input:repeat_delay"].intValue = 600;
configValues["input:natural_scroll"].intValue = 0;
configValues["input:numlock_by_default"].intValue = 0;
configValues["input:force_no_accel"].intValue = 0;
configValues["input:float_switch_override_focus"].intValue = 1;
configValues["input:left_handed"].intValue = 0;
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
configValues["input:scroll_button"].intValue = 0;
configValues["input:touchpad:natural_scroll"].intValue = 0;
configValues["input:touchpad:disable_while_typing"].intValue = 1;
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
2023-02-05 15:17:23 +01:00
configValues["input:touchpad:tap_button_map"].strValue = STRVAL_EMPTY;
configValues["input:touchpad:middle_button_emulation"].intValue = 0;
configValues["input:touchpad:tap-to-click"].intValue = 1;
configValues["input:touchpad:tap-and-drag"].intValue = 1;
configValues["input:touchpad:drag_lock"].intValue = 0;
configValues["input:touchpad:scroll_factor"].floatValue = 1.f;
configValues["input:touchdevice:transform"].intValue = 0;
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
configValues["input:tablet:transform"].intValue = 0;
configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
configValues["binds:pass_mouse_when_bound"].intValue = 0;
configValues["binds:scroll_event_delay"].intValue = 300;
configValues["binds:workspace_back_and_forth"].intValue = 0;
configValues["binds:allow_workspace_cycles"].intValue = 0;
2023-01-26 15:36:22 +01:00
configValues["binds:focus_preferred_method"].intValue = 0;
2022-07-26 14:50:21 +02:00
configValues["gestures:workspace_swipe"].intValue = 0;
configValues["gestures:workspace_swipe_fingers"].intValue = 3;
configValues["gestures:workspace_swipe_distance"].intValue = 300;
configValues["gestures:workspace_swipe_invert"].intValue = 1;
2022-07-07 11:52:12 +02:00
configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30;
configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f;
configValues["gestures:workspace_swipe_create_new"].intValue = 1;
configValues["gestures:workspace_swipe_forever"].intValue = 0;
2022-12-25 16:42:11 +01:00
configValues["gestures:workspace_swipe_numbered"].intValue = 0;
2022-07-07 11:52:12 +02:00
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;
cfgValues["accel_profile"].strValue = STRVAL_EMPTY;
cfgValues["kb_file"].strValue = STRVAL_EMPTY;
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;
2023-02-05 15:17:23 +01:00
cfgValues["tap_button_map"].strValue = STRVAL_EMPTY;
cfgValues["numlock_by_default"].intValue = 0;
cfgValues["disable_while_typing"].intValue = 1;
cfgValues["clickfinger_behavior"].intValue = 0;
2022-06-30 21:26:00 +02:00
cfgValues["middle_button_emulation"].intValue = 0;
cfgValues["tap-to-click"].intValue = 1;
cfgValues["tap-and-drag"].intValue = 1;
cfgValues["drag_lock"].intValue = 0;
cfgValues["left_handed"].intValue = 0;
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
cfgValues["scroll_button"].intValue = 0;
2022-12-21 16:11:39 +01:00
cfgValues["transform"].intValue = 0;
cfgValues["output"].strValue = STRVAL_EMPTY;
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
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("borderangle");
2022-07-28 13:28:43 +02:00
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
}
2022-09-25 20:07:48 +02:00
2022-07-28 13:28:43 +02:00
// init the values
animationConfig["global"] = {false, "default", "", 8.f, 1, &animationConfig["general"], nullptr};
2022-07-28 13:28:43 +02:00
CREATEANIMCFG("windows", "global");
CREATEANIMCFG("fade", "global");
CREATEANIMCFG("border", "global");
CREATEANIMCFG("borderangle", "global");
2022-07-28 13:28:43 +02:00
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-09-25 20:07:48 +02: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");
2022-12-18 00:05:15 +01:00
struct stat fileStat;
int err = stat(CONFIGPATH.c_str(), &fileStat);
2022-03-19 17:00:52 +01:00
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 */ && COMMAND.find("plugin:") != 0 /* plugins parsed later */) {
if (COMMAND[0] == '$') {
// register a dynamic var
Debug::log(LOG, "Registered dynamic var \"%s\" -> %s", COMMAND.c_str(), VALUE.c_str());
configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE));
std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
} 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);
2022-06-30 21:26:00 +02:00
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()) {
2022-12-21 16:11:39 +01:00
if (it->second.contains("touch_output") || it->second.contains("touch_transform")) {
parseError = "touch_output and touch_transform have been changed to output and transform respectively";
return;
}
2022-06-30 21:26:00 +02:00
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
return;
}
CONFIGENTRY = &it->second.at(CONFIGVAR);
} else if (COMMAND.find("plugin:") == 0) {
for (auto& [handle, pMap] : pluginConfigs) {
auto it = std::find_if(pMap->begin(), pMap->end(), [&](const auto& other) { return other.first == COMMAND; });
if (it == pMap->end()) {
2023-03-03 20:32:44 +01:00
continue; // May be in another plugin
}
CONFIGENTRY = &it->second;
}
if (!CONFIGENTRY)
return; // silent ignore
2022-06-30 21:26:00 +02:00
} 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-09-30 18:03:06 +02:00
if (CONFIGENTRY->intValue != -INT64_MAX) {
2022-03-17 15:53:45 +01:00
try {
CONFIGENTRY->intValue = configStringToInt(VALUE);
} catch (std::exception& e) {
2022-03-17 15:53:45 +01:00
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
2022-03-17 15:53:45 +01:00
}
2022-09-30 18:03:06 +02:00
} else if (CONFIGENTRY->floatValue != -__FLT_MAX__) {
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 + ">.";
}
2022-09-30 18:03:06 +02:00
} else if (CONFIGENTRY->vecValue != Vector2D(-__FLT_MAX__, -__FLT_MAX__)) {
try {
if (const auto SPACEPOS = VALUE.find(' '); SPACEPOS != std::string::npos) {
const auto X = VALUE.substr(0, SPACEPOS);
const auto Y = VALUE.substr(SPACEPOS + 1);
if (isNumber(X, true) && isNumber(Y, true)) {
CONFIGENTRY->vecValue = Vector2D(std::stof(X), std::stof(Y));
}
} else {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
2022-11-26 18:56:43 +01:00
} else if (CONFIGENTRY->data.get() != nullptr) {
switch (CONFIGENTRY->data->getDataType()) {
case CVD_TYPE_GRADIENT: {
2022-12-18 00:05:15 +01:00
CVarList varlist(VALUE, 0, ' ');
2022-11-26 18:56:43 +01:00
CGradientValueData* data = (CGradientValueData*)CONFIGENTRY->data.get();
data->m_vColors.clear();
for (auto& var : varlist) {
if (var.find("deg") != std::string::npos) {
// last arg
try {
data->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (PI / 180.0); // radians
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
break;
}
if (data->m_vColors.size() >= 10) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. Max colors in a gradient is 10.";
break;
}
try {
data->m_vColors.push_back(CColor(configStringToInt(var)));
2022-11-26 18:56:43 +01:00
} catch (std::exception& e) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
}
}
if (data->m_vColors.size() == 0) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. No colors provided.";
data->m_vColors.push_back(0); // transparent
}
break;
}
default: {
UNREACHABLE();
2022-11-26 18:56:43 +01:00
}
}
2022-03-17 15:53:45 +01:00
}
2022-12-01 14:36:07 +01:00
if (COMMAND == "decoration:screen_shader") {
const auto PATH = absolutePath(VALUE, configCurrentPath);
configPaths.push_back(PATH);
struct stat fileStat;
int err = stat(PATH.c_str(), &fileStat);
2022-12-01 14:36:07 +01:00
if (err != 0) {
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", PATH.c_str(), err, strerror(err));
return;
}
configModifyTimes[PATH] = fileStat.st_mtime;
}
2022-03-17 15:53:45 +01:00
}
void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
// Exec in the background dont wait for it.
2022-11-10 14:50:16 +01:00
g_pKeybindManager->spawn(args);
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;
2022-12-18 00:05:15 +01:00
const auto ARGS = CVarList(args);
2022-03-17 16:56:33 +01:00
newrule.name = ARGS[0];
2022-03-17 16:56:33 +01:00
if (ARGS[1] == "disable" || ARGS[1] == "disabled" || ARGS[1] == "addreserved" || ARGS[1] == "transform") {
if (ARGS[1] == "disable" || ARGS[1] == "disabled")
2022-04-27 17:46:07 +02:00
newrule.disabled = true;
else if (ARGS[1] == "transform") {
const auto TSF = std::stoi(ARGS[2]);
if (std::clamp(TSF, 0, 7) != TSF) {
Debug::log(ERR, "invalid transform %i in monitor", TSF);
parseError = "invalid transform";
return;
}
wl_output_transform transform = (wl_output_transform)std::stoi(ARGS[2]);
// overwrite if exists
for (auto& r : m_dMonitorRules) {
if (r.name == newrule.name) {
r.transform = transform;
return;
}
}
return;
} else if (ARGS[1] == "addreserved") {
int top = std::stoi(ARGS[2]);
2022-04-27 17:46:07 +02:00
int bottom = std::stoi(ARGS[3]);
2022-04-27 17:46:07 +02:00
int left = std::stoi(ARGS[4]);
2022-04-27 17:46:07 +02:00
int right = std::stoi(ARGS[5]);
2022-04-27 17:46:07 +02:00
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
std::erase_if(m_dMonitorRules, [&](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;
}
if (ARGS[1].find("pref") == 0) {
2022-07-30 22:54:29 +02:00
newrule.resolution = Vector2D();
} else if (ARGS[1].find("highrr") == 0) {
newrule.resolution = Vector2D(-1, -1);
} else if (ARGS[1].find("highres") == 0) {
newrule.resolution = Vector2D(-1, -2);
2022-07-30 22:54:29 +02:00
} else {
newrule.resolution.x = stoi(ARGS[1].substr(0, ARGS[1].find_first_of('x')));
newrule.resolution.y = stoi(ARGS[1].substr(ARGS[1].find_first_of('x') + 1, ARGS[1].find_first_of('@')));
2022-03-19 21:46:29 +01:00
if (ARGS[1].contains("@"))
newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1));
2022-08-03 21:06:51 +02:00
}
2022-03-17 16:56:33 +01:00
if (ARGS[2].find("auto") == 0) {
2022-08-04 11:10:26 +02:00
newrule.offset = Vector2D(-1, -1);
} else {
newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x')));
newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].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.";
2022-08-04 11:10:26 +02:00
newrule.offset = Vector2D();
}
2022-08-03 21:06:51 +02:00
}
2022-12-14 18:57:18 +01:00
if (ARGS[3].find("auto") == 0) {
newrule.scale = -1;
} else {
newrule.scale = stof(ARGS[3]);
2022-03-17 16:56:33 +01:00
2022-12-14 18:57:18 +01:00
if (newrule.scale < 0.25f) {
parseError = "not a valid scale.";
2022-12-14 18:57:18 +01:00
newrule.scale = 1;
}
2022-08-03 21:06:51 +02:00
}
int argno = 4;
2022-04-21 22:15:42 +02:00
while (ARGS[argno] != "") {
if (ARGS[argno] == "mirror") {
newrule.mirrorOf = ARGS[argno + 1];
argno++;
2022-10-27 14:26:47 +02:00
} else if (ARGS[argno] == "bitdepth") {
newrule.enable10bit = ARGS[argno + 1] == "10";
argno++;
} else if (ARGS[argno] == "transform") {
newrule.transform = (wl_output_transform)std::stoi(ARGS[argno + 1]);
argno++;
} else if (ARGS[argno] == "workspace") {
m_mDefaultWorkspaces[newrule.name] = ARGS[argno + 1];
argno++;
2022-09-13 15:25:42 +02:00
} else {
Debug::log(ERR, "Config error: invalid monitor syntax");
parseError = "invalid syntax at \"" + ARGS[argno] + "\"";
2022-09-13 15:25:42 +02:00
return;
}
argno++;
2022-04-21 22:15:42 +02:00
}
std::erase_if(m_dMonitorRules, [&](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) {
2022-12-18 00:05:15 +01:00
const auto ARGS = CVarList(args);
2022-04-23 21:47:16 +02:00
std::string bezierName = ARGS[0];
2022-04-23 21:47:16 +02:00
if (ARGS[1] == "")
2022-08-09 18:15:37 +02:00
parseError = "too few arguments";
float p1x = std::stof(ARGS[1]);
if (ARGS[2] == "")
2022-08-09 18:15:37 +02:00
parseError = "too few arguments";
float p1y = std::stof(ARGS[2]);
if (ARGS[3] == "")
2022-08-09 18:15:37 +02:00
parseError = "too few arguments";
float p2x = std::stof(ARGS[3]);
if (ARGS[4] == "")
2022-08-09 18:15:37 +02:00
parseError = "too few arguments";
float p2y = std::stof(ARGS[4]);
if (ARGS[5] != "")
2022-08-09 18:15:37 +02:00
parseError = "too many arguments";
2022-04-23 21:47:16 +02:00
g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
}
void CConfigManager::setAnimForChildren(SAnimationPropertyConfig* const ANIM) {
2022-07-28 13:28:43 +02:00
for (auto& [name, anim] : animationConfig) {
if (anim.pParentAnimation == ANIM && !anim.overridden) {
// if a child isnt overridden, set the values of the parent
2022-07-28 13:28:43 +02:00
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) {
const auto ARGS = CVarList(args);
2022-05-14 15:56:01 +02:00
// Master on/off
// anim name
const auto ANIMNAME = ARGS[0];
2022-09-25 20:07:48 +02:00
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;
}
PANIM->second.overridden = true;
PANIM->second.pValues = &PANIM->second;
2022-07-28 13:28:43 +02:00
2022-05-14 15:56:01 +02:00
// on/off
PANIM->second.internalEnabled = ARGS[1] == "1";
2022-05-14 15:56:01 +02:00
if (ARGS[1] != "0" && ARGS[1] != "1") {
2022-08-07 19:28:46 +02:00
parseError = "invalid animation on/off state";
}
2022-07-28 13:28:43 +02:00
// speed
if (isNumber(ARGS[2], true)) {
PANIM->second.internalSpeed = std::stof(ARGS[2]);
2022-08-07 19:28:46 +02:00
if (PANIM->second.internalSpeed <= 0) {
parseError = "invalid speed";
2022-08-07 19:28:46 +02:00
PANIM->second.internalSpeed = 1.f;
}
2022-07-28 13:28:43 +02:00
} else {
PANIM->second.internalSpeed = 10.f;
parseError = "invalid speed";
2022-07-28 13:28:43 +02:00
}
2022-05-14 15:56:01 +02:00
// curve
PANIM->second.internalBezier = ARGS[3];
2022-05-14 16:43:30 +02:00
if (!g_pAnimationManager->bezierExists(ARGS[3])) {
parseError = "no such bezier";
2022-08-07 19:28:46 +02:00
PANIM->second.internalBezier = "default";
}
2022-05-14 16:43:30 +02:00
// style
PANIM->second.internalStyle = ARGS[4];
2022-07-28 13:28:43 +02:00
if (ARGS[4] != "") {
const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]);
2022-08-07 19:28:46 +02:00
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;
bool release = false;
bool repeat = false;
bool mouse = false;
const auto BINDARGS = command.substr(4);
2022-07-20 22:45:06 +02:00
for (auto& arg : BINDARGS) {
2022-07-20 22:33:43 +02:00
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-09-19 20:04:48 +02:00
} else if (arg == 'm') {
mouse = 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-09-19 20:04:48 +02:00
if (mouse && (repeat || release || locked)) {
parseError = "flag m is exclusive";
return;
}
2022-10-03 17:38:05 +02:00
const auto ARGS = CVarList(value, 4);
2022-03-19 17:48:18 +01:00
2022-10-03 22:01:08 +02:00
if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse)) {
parseError = "bind: too few args";
return;
} else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse)) {
parseError = "bind: too many args";
return;
}
2022-03-19 17:48:18 +01:00
const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
const auto MODSTR = ARGS[0];
2022-03-19 17:48:18 +01:00
const auto KEY = ARGS[1];
2022-03-19 17:48:18 +01:00
2022-12-18 00:05:15 +01:00
auto HANDLER = ARGS[2];
const auto COMMAND = mouse ? HANDLER : ARGS[3];
2022-09-19 20:04:48 +02:00
if (mouse)
HANDLER = "mouse";
2022-03-19 17:48:18 +01:00
2022-09-21 18:41:19 +02:00
// to lower
std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower);
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-07-08 09:27:17 +02:00
if (KEY != "") {
if (isNumber(KEY) && std::stoi(KEY) > 9)
2022-09-19 20:04:48 +02:00
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
2023-03-23 14:05:23 +01:00
else if (KEY.find("code:") == 0 && isNumber(KEY.substr(5)))
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
2022-07-08 09:27:17 +02:00
else
2022-09-19 20:04:48 +02:00
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
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) {
const auto ARGS = CVarList(value);
2022-04-21 17:06:43 +02:00
const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
2022-04-21 17:06:43 +02:00
const auto KEY = ARGS[1];
2022-04-21 17:06:43 +02:00
g_pKeybindManager->removeKeybind(MOD, KEY);
}
2022-09-06 11:57:11 +02:00
bool windowRuleValid(const std::string& RULE) {
return !(RULE != "float" && RULE != "tile" && RULE.find("opacity") != 0 && RULE.find("move") != 0 && RULE.find("size") != 0 && RULE.find("minsize") != 0 &&
RULE.find("maxsize") != 0 && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0 && RULE.find("idleinhibit") != 0 && RULE != "nofocus" && RULE != "noblur" &&
RULE != "noshadow" && RULE != "noborder" && RULE != "center" && RULE != "opaque" && RULE != "forceinput" && RULE != "fullscreen" && RULE != "nofullscreenrequest" &&
2022-12-28 15:39:17 +01:00
RULE != "nomaxsize" && RULE != "pin" && RULE != "noanim" && RULE != "dimaround" && RULE != "windowdance" && RULE != "maximize" && RULE.find("animation") != 0 &&
2023-03-26 03:00:24 +02:00
RULE.find("rounding") != 0 && RULE.find("workspace") != 0 && RULE.find("bordercolor") != 0 && RULE != "forcergbx");
2022-09-06 11:57:11 +02:00
}
2023-01-25 16:34:13 +01:00
bool layerRuleValid(const std::string& RULE) {
2023-03-18 00:16:13 +01:00
return !(RULE != "noanim" && RULE != "blur" && RULE != "ignorezero");
2023-01-25 16:34:13 +01:00
}
2022-09-06 11:57:11 +02:00
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
2022-09-06 11:57:11 +02:00
// check rule and value
if (RULE == "" || VALUE == "") {
return;
}
2022-11-03 20:52:43 +01:00
if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) { return other.szValue == VALUE; });
2022-11-03 20:52:43 +01:00
return;
}
2022-09-06 11:57:11 +02:00
// 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
}
2023-01-25 16:34:13 +01:00
void CConfigManager::handleLayerRule(const std::string& command, const std::string& value) {
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
// check rule and value
2023-03-18 00:16:13 +01:00
if (RULE == "" || VALUE == "")
2023-01-25 16:34:13 +01:00
return;
if (RULE == "unset") {
std::erase_if(m_dLayerRules, [&](const SLayerRule& other) { return other.targetNamespace == VALUE; });
return;
}
if (!layerRuleValid(RULE)) {
Debug::log(ERR, "Invalid rule found: %s", RULE.c_str());
parseError = "Invalid rule found: " + RULE;
return;
}
m_dLayerRules.push_back({VALUE, RULE});
2023-03-18 00:16:13 +01:00
for (auto& m : g_pCompositor->m_vMonitors)
for (auto& lsl : m->m_aLayerSurfaceLayers)
for (auto& ls : lsl)
ls->applyRules();
2023-01-25 16:34:13 +01:00
}
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);
2022-09-06 11:57:11 +02:00
2022-11-03 20:52:43 +01:00
if (!windowRuleValid(RULE) && RULE != "unset") {
2022-09-06 11:57:11 +02:00
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:");
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
const auto PINNEDPOS = VALUE.find("pinned:");
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 && FULLSCREENPOS == std::string::npos &&
PINNEDPOS == 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;
if (FULLSCREENPOS > pos && FULLSCREENPOS < min)
min = FULLSCREENPOS;
if (PINNEDPOS > pos && PINNEDPOS < min)
min = PINNEDPOS;
2022-09-06 11:57:11 +02:00
result = result.substr(0, min - pos);
result = removeBeginEndSpacesTabs(result);
2022-09-06 11:57:11 +02:00
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;
}
if (FULLSCREENPOS != std::string::npos) {
rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
}
if (PINNEDPOS != std::string::npos) {
rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
}
2022-11-03 20:52:43 +01:00
if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
if (!other.v2) {
return other.szClass == rule.szClass && !rule.szClass.empty();
} else {
if (!rule.szClass.empty() && rule.szClass != other.szClass) {
return false;
}
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle) {
return false;
}
if (rule.bX11 != -1 && rule.bX11 != other.bX11) {
return false;
}
if (rule.bFloating != -1 && rule.bFloating != other.bFloating) {
return false;
}
if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen) {
return false;
}
if (rule.bPinned != -1 && rule.bPinned != other.bPinned) {
return false;
}
2022-11-03 20:52:43 +01:00
return true;
}
});
return;
}
2022-09-06 11:57:11 +02:00
m_dWindowRules.push_back(rule);
2022-03-24 18:22:01 +01:00
}
void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
2023-02-25 18:39:26 +01:00
const bool BYADDRESS = name.find("address:") == 0;
std::string matchName = name;
if (BYADDRESS) {
2023-03-09 15:24:06 +01:00
matchName = matchName.substr(8);
2023-02-25 18:39:26 +01:00
}
for (auto& m : g_pCompositor->m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLayers) {
for (auto& ls : lsl) {
2023-02-25 18:39:26 +01:00
if (BYADDRESS) {
2023-04-17 18:35:28 +02:00
if (getFormat("0x%lx", ls.get()) == matchName)
2023-02-25 18:39:26 +01:00
ls->forceBlur = forceBlur;
} else if (ls->szNamespace == matchName)
ls->forceBlur = forceBlur;
}
}
}
}
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 = removeBeginEndSpacesTabs(value.substr(7));
if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
updateBlurredLS(TOREMOVE, false);
2022-07-15 13:29:56 +02:00
return;
}
2022-07-06 22:12:03 +02:00
m_dBlurLSNamespaces.emplace_back(value);
updateBlurredLS(value, true);
2022-07-06 22:12:03 +02:00
}
2022-03-20 16:01:47 +01:00
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
const auto ARGS = CVarList(value);
2022-03-20 16:01:47 +01:00
m_mDefaultWorkspaces[ARGS[0]] = ARGS[1];
2022-03-20 16:01:47 +01:00
}
2022-06-22 20:23:20 +02:00
void CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
2022-09-25 20:07:48 +02:00
if (submap == "reset")
2022-06-22 20:23:20 +02:00
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);
2022-05-16 10:09:20 +02:00
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;
2022-05-16 10:09:20 +02:00
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 ARGS = CVarList(value);
2022-09-12 21:05:52 +02:00
const auto FOUND = std::find_if(boundWorkspaces.begin(), boundWorkspaces.end(), [&](const auto& other) { return other.first == ARGS[0]; });
2022-09-24 14:42:18 +02:00
if (FOUND != boundWorkspaces.end()) {
FOUND->second = ARGS[1];
2022-09-24 14:42:18 +02:00
return;
}
boundWorkspaces.push_back({ARGS[0], ARGS[1]});
2022-09-12 21:05:52 +02:00
}
2023-03-05 14:12:01 +01:00
void CConfigManager::handleEnv(const std::string& command, const std::string& value) {
if (!isFirstLaunch)
return;
const auto ARGS = CVarList(value, 2);
if (ARGS[0].empty()) {
parseError = "env empty";
return;
}
setenv(ARGS[0].c_str(), ARGS[1].c_str(), 1);
2023-03-05 14:15:12 +01:00
if (command.back() == 'd') {
// dbus
const auto CMD =
#ifdef USES_SYSTEMD
"systemctl --user import-environment " + ARGS[0] +
2023-03-05 14:15:12 +01:00
" && hash dbus-update-activation-environment 2>/dev/null && "
#endif
2023-03-05 14:15:12 +01:00
"dbus-update-activation-environment --systemd " +
ARGS[0];
handleRawExec("", CMD.c_str());
}
2023-03-05 14:12:01 +01:00
}
2022-04-21 16:56:27 +02:00
std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE, bool dynamic) {
if (dynamic) {
parseError = "";
currentCategory = "";
}
2022-04-21 16:56:27 +02:00
int needsLayoutRecalc = COMMAND == "monitor"; // 0 - no, 1 - yes, 2 - maybe
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);
}
} else if (COMMAND == "monitor")
handleMonitor(COMMAND, VALUE);
else if (COMMAND.find("bind") == 0)
handleBind(COMMAND, VALUE);
else if (COMMAND == "unbind")
handleUnbind(COMMAND, VALUE);
else if (COMMAND == "workspace")
handleDefaultWorkspace(COMMAND, VALUE);
else if (COMMAND == "windowrule")
handleWindowRule(COMMAND, VALUE);
else if (COMMAND == "windowrulev2")
handleWindowRuleV2(COMMAND, VALUE);
2023-01-25 16:34:13 +01:00
else if (COMMAND == "layerrule")
handleLayerRule(COMMAND, VALUE);
else if (COMMAND == "bezier")
handleBezier(COMMAND, VALUE);
else if (COMMAND == "animation")
handleAnimation(COMMAND, VALUE);
else if (COMMAND == "source")
handleSource(COMMAND, VALUE);
else if (COMMAND == "submap")
handleSubmap(COMMAND, VALUE);
else if (COMMAND == "blurls")
handleBlurLS(COMMAND, VALUE);
else if (COMMAND == "wsbind")
handleBindWS(COMMAND, VALUE);
2023-03-05 14:15:12 +01:00
else if (COMMAND.find("env") == 0)
2023-03-05 14:12:01 +01:00
handleEnv(COMMAND, VALUE);
else {
2022-05-14 15:56:01 +02:00
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
needsLayoutRecalc = 2;
}
2022-04-21 16:56:27 +02:00
if (dynamic) {
std::string retval = parseError;
parseError = "";
// invalidate layouts if they changed
if (needsLayoutRecalc) {
if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.find("dwindle:") == 0 || COMMAND.find("master:") == 0) {
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
2023-04-04 23:13:31 +02:00
// manual crash
if (configValues["debug:manual_crash"].intValue && !m_bManualCrashInitiated) {
m_bManualCrashInitiated = true;
if (g_pHyprNotificationOverlay) {
g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000,
ICON_INFO);
}
2023-04-04 23:13:31 +02:00
} else if (m_bManualCrashInitiated && !configValues["debug:manual_crash"].intValue) {
// cowabunga it is
g_pHyprRenderer->initiateManualCrash();
}
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);
2023-03-05 15:54:26 +01:00
bool found = false;
for (auto& [var, value] : configDynamicVars) {
2022-05-16 09:38:42 +02:00
if (STRAFTERDOLLAR.find(var) == 0) {
line.replace(dollarPlace, var.length() + 1, value);
2023-03-05 15:54:26 +01:00
found = true;
2022-05-16 09:38:42 +02:00
break;
}
}
2023-03-05 15:54:26 +01:00
if (!found) {
// maybe env?
for (auto& [var, value] : environmentVariables) {
if (STRAFTERDOLLAR.find(var) == 0) {
line.replace(dollarPlace, var.length() + 1, value);
break;
}
}
}
2022-05-16 09:38:42 +02:00
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
2022-10-25 15:32:25 +02:00
if (line[0] == '#')
2022-03-17 15:53:45 +01:00
return;
2022-10-25 15:32:25 +02:00
// now, cut the comment off. ## is an escape.
for (long unsigned int i = 1; i < line.length(); ++i) {
if (line[i] == '#') {
if (i + 1 < line.length() && line[i + 1] != '#') {
line = line.substr(0, i);
break; // no need to parse more
}
i++;
}
}
size_t startPos = 0;
2022-11-06 15:28:15 +01:00
while ((startPos = line.find("##", startPos)) != std::string::npos && startPos < line.length() - 1 && startPos > 0) {
2022-10-25 15:32:25 +02:00
line.replace(startPos, 2, "#");
startPos++;
}
2022-03-17 15:53:45 +01:00
line = removeBeginEndSpacesTabs(line);
2022-03-17 15:53:45 +01:00
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 {
2022-04-19 18:42:26 +02:00
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 = "";
2022-09-25 20:07:48 +02:00
else
2022-08-27 23:12:01 +02:00
currentCategory = currentCategory.substr(0, LASTSEP);
2022-09-25 20:07:48 +02:00
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-04-18 13:25:27 +02:00
//
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
2022-09-25 20:07:48 +02:00
// 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();
2022-12-18 00:05:15 +01:00
std::string CONFIGPATH;
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-09-25 20:07:48 +02:00
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;
2022-03-17 15:53:45 +01:00
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();
2022-10-05 22:21:22 +02:00
g_pInputManager->setPointerConfigs();
g_pInputManager->setTouchDeviceConfigs();
2022-12-21 16:11:39 +01:00
g_pInputManager->setTabletConfigs();
}
2022-03-24 21:05:34 +01:00
2022-12-01 14:36:07 +01:00
if (!isFirstLaunch)
g_pHyprOpenGL->m_bReloadScreenShader = true;
// parseError will be displayed next frame
if (parseError != "")
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
else if (configValues["autogenerated"].intValue == 1)
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + CONFIGPATH + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland",
CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
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-07-27 12:32:00 +02:00
// check
2022-12-02 19:45:45 +01:00
performMonitorReload();
ensureMonitorStatus();
2022-10-22 22:45:17 +02:00
ensureVRR();
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);
2023-04-04 15:49:58 +02:00
// manual crash
if (configValues["debug:manual_crash"].intValue && !m_bManualCrashInitiated) {
m_bManualCrashInitiated = true;
g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000, ICON_INFO);
} else if (m_bManualCrashInitiated && !configValues["debug:manual_crash"].intValue) {
// cowabunga it is
g_pHyprRenderer->initiateManualCrash();
}
2023-03-24 20:37:37 +01:00
Debug::disableStdout = !configValues["debug:enable_stdout_logs"].intValue;
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-09-25 20:07:48 +02:00
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() {
std::string CONFIGPATH;
if (g_pCompositor->explicitConfigPath.empty()) {
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;
}
2023-02-09 16:29:02 +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);
2022-05-16 10:09:20 +02:00
if (err != 0) {
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", cf.c_str(), err, strerror(err));
continue;
2022-05-16 10:09:20 +02:00
}
// check if we need to reload cfg
if (fileStat.st_mtime != configModifyTimes[cf] || m_bForceReload) {
parse = true;
2022-05-16 10:09:20 +02:00
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);
2022-12-18 00:05:15 +01:00
SConfigValue copy = configValues[val];
2022-03-17 15:53:45 +01:00
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-12-18 00:05:15 +01:00
const auto it = deviceConfigs.find(dev);
2022-06-30 21:26:00 +02:00
if (it == deviceConfigs.end()) {
2022-12-03 16:56:07 +01:00
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", dev.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;
2023-01-17 11:47:39 +01:00
if (cv.first == "input:" + val || cv.first == "input:touchpad:" + cv.first || cv.first == "input:touchdevice:" + val || cv.first == "input:tablet:" + cv.first ||
cv.first == "input:tablet:" + val) {
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) {
auto VAL = getConfigValueSafe(v).strValue;
2022-05-06 14:30:35 +02:00
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) {
auto VAL = getConfigValueSafeDevice(dev, v).strValue;
2022-06-30 21:26:00 +02:00
if (VAL == STRVAL_EMPTY)
return "";
return VAL;
}
void CConfigManager::setInt(const std::string& v, int val) {
configValues[v].intValue = val;
}
void CConfigManager::setFloat(const std::string& v, float val) {
configValues[v].floatValue = val;
}
void CConfigManager::setString(const std::string& v, const std::string& val) {
configValues[v].strValue = val;
}
SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const std::string& displayName) {
2022-03-17 16:56:33 +01:00
SMonitorRule* found = nullptr;
for (auto& r : m_dMonitorRules) {
if (r.name == name ||
(r.name.find("desc:") == 0 &&
(r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
2022-03-17 16:56:33 +01:00
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) {
2022-10-05 18:38:36 +02:00
if (r.name == "") {
2022-03-17 16:56:33 +01:00
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.");
2022-12-14 19:00:04 +01:00
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;
2022-12-18 00:05:15 +01:00
std::string title = g_pXWaylandManager->getTitle(pWindow);
std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow);
2022-03-24 18:22:01 +01:00
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;
}
if (rule.bFullscreen != -1) {
if (pWindow->m_bIsFullscreen != rule.bFullscreen)
continue;
}
if (rule.bPinned != -1) {
if (pWindow->m_bPinned != rule.bPinned)
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
2023-04-17 18:35:28 +02:00
Debug::log(LOG, "Window rule %s -> %s matched %lx [%s]", rule.szRule.c_str(), rule.szValue.c_str(), pWindow, pWindow->m_szTitle.c_str());
2022-03-24 18:22:01 +01:00
returns.push_back(rule);
}
const uint64_t PID = pWindow->getPID();
bool anyExecFound = false;
2022-11-10 14:39:23 +01:00
for (auto& er : execRequestedRules) {
if (er.iPid == PID) {
returns.push_back({er.szRule, "execRule"});
anyExecFound = true;
}
}
if (anyExecFound) // remove exec rules to unclog searches in the future, why have the garbage here.
execRequestedRules.erase(std::remove_if(execRequestedRules.begin(), execRequestedRules.end(), [&](const SExecRequestedRule& other) { return other.iPid == PID; }));
2022-03-24 18:22:01 +01:00
return returns;
2022-04-12 20:02:57 +02:00
}
2023-01-25 16:34:13 +01:00
std::vector<SLayerRule> CConfigManager::getMatchingRules(SLayerSurface* pLS) {
std::vector<SLayerRule> returns;
if (!pLS->layerSurface || pLS->fadingOut)
return returns;
2023-01-25 16:34:13 +01:00
for (auto& lr : m_dLayerRules) {
2023-03-18 00:33:03 +01:00
if (lr.targetNamespace.find("address:0x") == 0) {
2023-04-17 18:35:28 +02:00
if (getFormat("address:0x%lx", pLS) != lr.targetNamespace)
2023-03-18 00:33:03 +01:00
continue;
} else {
std::regex NSCHECK(lr.targetNamespace);
2023-01-25 16:34:13 +01:00
2023-03-18 00:33:03 +01:00
if (!pLS->layerSurface->_namespace || !std::regex_search(pLS->layerSurface->_namespace, NSCHECK))
continue;
}
2023-01-25 16:34:13 +01:00
// hit
returns.push_back(lr);
}
2023-03-18 00:36:36 +01:00
if (pLS->layerSurface->_namespace && shouldBlurLS(pLS->layerSurface->_namespace))
returns.push_back({pLS->layerSurface->_namespace, "blur"});
2023-01-25 16:34:13 +01:00
return returns;
}
2022-04-12 20:02:57 +02:00
void CConfigManager::dispatchExecOnce() {
if (firstExecDispatched || isFirstLaunch)
return;
// update dbus env
2023-03-24 04:21:38 +01:00
if (g_pCompositor->m_sWLRSession)
handleRawExec(
"",
#ifdef USES_SYSTEMD
2023-03-24 04:21:38 +01:00
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
#endif
2023-03-24 04:21:38 +01:00
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE");
2022-04-12 20:02:57 +02:00
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();
2022-10-05 22:21:22 +02:00
g_pInputManager->setPointerConfigs();
g_pInputManager->setTouchDeviceConfigs();
2022-12-21 16:11:39 +01:00
g_pInputManager->setTabletConfigs();
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());
}
2023-03-20 16:02:47 +01:00
// check for user's possible errors with their setup and notify them if needed
g_pCompositor->performUserChecks();
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) {
2023-03-15 16:11:41 +01:00
if (!m->output)
continue;
2022-10-05 11:22:33 +02:00
auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
2022-09-13 15:25:42 +02:00
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
// ensure mirror
m->setMirror(rule.mirrorOf);
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-12-02 19:45:45 +01:00
if (!g_pCompositor->m_vMonitors.empty()) // reset unsafe state if we have monitors
g_pCompositor->m_bUnsafeState = false;
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(const std::string& val) {
2022-04-23 14:16:02 +02:00
return &configValues[val];
}
2022-06-30 21:26:00 +02:00
SConfigValue* CConfigManager::getConfigValuePtrSafe(const std::string& val) {
2022-08-11 21:16:38 +02:00
const auto IT = configValues.find(val);
if (IT == configValues.end()) {
// maybe plugin
for (auto& [pl, pMap] : pluginConfigs) {
const auto PLIT = pMap->find(val);
if (PLIT != pMap->end())
return &PLIT->second;
}
2022-08-11 21:16:38 +02:00
return nullptr;
}
2022-08-11 21:16:38 +02:00
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::ensureMonitorStatus() {
2022-07-27 12:32:00 +02:00
for (auto& rm : g_pCompositor->m_vRealMonitors) {
2023-03-16 15:03:40 +01:00
if (!rm->output)
continue;
2022-10-05 11:22:33 +02:00
auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : "");
2022-07-27 12:32:00 +02:00
if (rule.disabled == rm->m_bEnabled) {
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
void CConfigManager::ensureVRR(CMonitor* pMonitor) {
2023-02-14 18:08:42 +01:00
static auto* const PVRR = &getConfigValuePtr("misc:vrr")->intValue;
2023-02-14 18:08:42 +01:00
static auto ensureVRRForDisplay = [&](CMonitor* m) -> void {
2023-03-16 15:03:40 +01:00
if (!m->output)
return;
2023-02-14 18:08:42 +01:00
if (*PVRR == 0) {
if (m->vrrActive) {
2022-10-22 22:45:17 +02:00
wlr_output_enable_adaptive_sync(m->output, 0);
2023-02-14 18:08:42 +01:00
if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s in ensureVRR -> false", m->output->name);
}
2022-10-22 22:45:17 +02:00
}
2023-02-14 18:08:42 +01:00
m->vrrActive = false;
return;
} else if (*PVRR == 1) {
if (!m->vrrActive) {
wlr_output_enable_adaptive_sync(m->output, 1);
2022-10-22 22:45:17 +02:00
2023-02-14 18:08:42 +01:00
if (!wlr_output_test(m->output)) {
Debug::log(LOG, "Pending output %s does not accept VRR.", m->output->name);
wlr_output_enable_adaptive_sync(m->output, 0);
}
if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s in ensureVRR -> true", m->output->name);
}
}
m->vrrActive = true;
return;
} else if (*PVRR == 2) {
/* fullscreen */
2022-10-22 22:45:17 +02:00
m->vrrActive = true;
2023-02-14 18:08:42 +01:00
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m->activeWorkspace);
2022-10-22 22:45:17 +02:00
2023-02-14 18:08:42 +01:00
if (!PWORKSPACE)
return; // ???
2022-10-22 22:45:17 +02:00
2023-02-14 18:08:42 +01:00
if (PWORKSPACE->m_bHasFullscreenWindow && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) {
wlr_output_enable_adaptive_sync(m->output, 1);
if (!wlr_output_test(m->output)) {
Debug::log(LOG, "Pending output %s does not accept VRR.", m->output->name);
wlr_output_enable_adaptive_sync(m->output, 0);
}
2022-10-22 22:45:17 +02:00
2023-02-14 18:08:42 +01:00
if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s in ensureVRR -> true", m->output->name);
}
} else if (!PWORKSPACE->m_bHasFullscreenWindow && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) {
wlr_output_enable_adaptive_sync(m->output, 0);
if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s in ensureVRR -> false", m->output->name);
}
}
2022-10-22 22:45:17 +02:00
}
};
if (pMonitor) {
ensureVRRForDisplay(pMonitor);
return;
}
for (auto& m : g_pCompositor->m_vMonitors) {
ensureVRRForDisplay(m.get());
2022-10-22 22:45:17 +02:00
}
}
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-12-01 14:36:07 +01:00
2023-01-05 23:30:13 +01:00
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
2022-08-19 20:01:51 +02:00
}
2022-09-12 21:05:52 +02:00
CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) {
for (auto& [ws, mon] : boundWorkspaces) {
2022-09-12 21:05:52 +02:00
const auto WSNAME = ws.find("name:") == 0 ? ws.substr(5) : ws;
if (WSNAME == wsname) {
return g_pCompositor->getMonitorFromString(mon);
}
}
return nullptr;
}
2022-11-10 14:39:23 +01:00
std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) {
2022-12-09 18:17:02 +01:00
for (auto& [ws, mon] : boundWorkspaces) {
const auto WSNAME = ws.find("name:") == 0 ? ws.substr(5) : ws;
if (WSNAME == wsname) {
return mon;
}
}
return "";
}
void CConfigManager::addExecRule(const SExecRequestedRule& rule) {
2022-11-10 14:39:23 +01:00
execRequestedRules.push_back(rule);
}
2022-11-26 18:56:43 +01:00
ICustomConfigValueData::~ICustomConfigValueData() {
; // empty
}
2023-01-25 16:16:28 +01:00
std::unordered_map<std::string, SAnimationPropertyConfig> CConfigManager::getAnimationConfig() {
return animationConfig;
}
void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value) {
auto CONFIGMAPIT = std::find_if(pluginConfigs.begin(), pluginConfigs.end(), [&](const auto& other) { return other.first == handle; });
if (CONFIGMAPIT == pluginConfigs.end()) {
pluginConfigs.emplace(
std::pair<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>>(handle, std::make_unique<std::unordered_map<std::string, SConfigValue>>()));
CONFIGMAPIT = std::find_if(pluginConfigs.begin(), pluginConfigs.end(), [&](const auto& other) { return other.first == handle; });
}
(*CONFIGMAPIT->second)[name] = value;
}
void CConfigManager::removePluginConfig(HANDLE handle) {
std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; });
}
std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {
const auto IT = std::find_if(m_mDefaultWorkspaces.begin(), m_mDefaultWorkspaces.end(), [&](const auto& other) { return other.first == name; });
if (IT == m_mDefaultWorkspaces.end())
return "";
return IT->second;
}