Hyprland/src/config/ConfigManager.cpp

2349 lines
88 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 <string>
2022-03-17 15:53:45 +01:00
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <glob.h>
2022-03-17 15:53:45 +01:00
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
2022-03-17 15:53:45 +01:00
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);
configValues["general:col.nogroup_border"].data = std::make_shared<CGradientValueData>(0xffffaaff);
configValues["general:col.nogroup_border_active"].data = std::make_shared<CGradientValueData>(0xffff00ff);
configValues["group:col.border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
configValues["group:col.border_inactive"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["group:col.border_locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
configValues["group:col.border_locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500);
configValues["group:groupbar:col.active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
configValues["group:groupbar:col.inactive"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["group:groupbar:col.locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
configValues["group:groupbar:col.locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500);
2022-11-26 18:56:43 +01:00
setDefaultVars();
2022-07-28 13:28:43 +02:00
setDefaultAnimationVars();
configPaths.emplace_back(getMainConfigPath());
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();
}
std::string CConfigManager::getConfigDir() {
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
std::string configPath;
if (!xdgConfigHome)
configPath = getenv("HOME") + std::string("/.config");
else
configPath = xdgConfigHome;
return configPath;
}
std::string CConfigManager::getMainConfigPath() {
if (!g_pCompositor->explicitConfigPath.empty())
return g_pCompositor->explicitConfigPath;
return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
}
2023-03-05 15:54:26 +01:00
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);
((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444);
((CGradientValueData*)configValues["general:col.nogroup_border_active"].data.get())->reset(0xffff00ff);
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";
configValues["general:allow_tearing"].intValue = 0;
2022-09-25 20:07:48 +02:00
configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0;
configValues["misc:force_hypr_chan"].intValue = 0;
configValues["misc:force_default_wallpaper"].intValue = -1;
configValues["misc:vfr"].intValue = 1;
configValues["misc:vrr"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
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:render_ahead_of_time"].intValue = 0;
configValues["misc:render_ahead_safezone"].intValue = 1;
configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
configValues["misc:cursor_zoom_rigid"].intValue = 0;
configValues["misc:allow_session_lock_restore"].intValue = 0;
configValues["misc:close_special_on_empty"].intValue = 1;
configValues["misc:background_color"].intValue = 0xff111111;
configValues["misc:new_window_takes_over_fullscreen"].intValue = 0;
((CGradientValueData*)configValues["group:col.border_active"].data.get())->reset(0x66ffff00);
((CGradientValueData*)configValues["group:col.border_inactive"].data.get())->reset(0x66777700);
((CGradientValueData*)configValues["group:col.border_locked_active"].data.get())->reset(0x66ff5500);
((CGradientValueData*)configValues["group:col.border_locked_inactive"].data.get())->reset(0x66775500);
configValues["group:insert_after_current"].intValue = 1;
configValues["group:focus_removed_window"].intValue = 1;
configValues["group:groupbar:font_family"].strValue = "Sans";
configValues["group:groupbar:font_size"].intValue = 8;
configValues["group:groupbar:gradients"].intValue = 1;
configValues["group:groupbar:render_titles"].intValue = 1;
configValues["group:groupbar:scrolling"].intValue = 1;
configValues["group:groupbar:text_color"].intValue = 0xffffffff;
((CGradientValueData*)configValues["group:groupbar:col.active"].data.get())->reset(0x66ffff00);
((CGradientValueData*)configValues["group:groupbar:col.inactive"].data.get())->reset(0x66777700);
((CGradientValueData*)configValues["group:groupbar:col.locked_active"].data.get())->reset(0x66ff5500);
((CGradientValueData*)configValues["group:groupbar:col.locked_inactive"].data.get())->reset(0x66775500);
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["debug:suppress_errors"].intValue = 0;
configValues["debug:watchdog_timeout"].intValue = 5;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur:enabled"].intValue = 1;
configValues["decoration:blur:size"].intValue = 8;
configValues["decoration:blur:passes"].intValue = 1;
configValues["decoration:blur:ignore_opacity"].intValue = 0;
configValues["decoration:blur:new_optimizations"].intValue = 1;
configValues["decoration:blur:xray"].intValue = 0;
configValues["decoration:blur:contrast"].floatValue = 0.8916;
configValues["decoration:blur:brightness"].floatValue = 1.0;
configValues["decoration:blur:vibrancy"].floatValue = 0.1696;
configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
configValues["decoration:blur:noise"].floatValue = 0.0117;
configValues["decoration:blur:special"].intValue = 0;
configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 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;
configValues["decoration:dim_special"].floatValue = 0.2f;
configValues["decoration:dim_around"].floatValue = 0.4f;
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
2023-05-06 02:02:18 +02:00
configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:force_split"].intValue = 0;
configValues["dwindle:permanent_direction_override"].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;
configValues["dwindle:default_split_ratio"].floatValue = 1.f;
configValues["dwindle:smart_split"].intValue = 0;
configValues["dwindle:smart_resizing"].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: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;
configValues["master:smart_resizing"].intValue = 1;
configValues["master:drop_at_cursor"].intValue = 1;
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:mouse_refocus"].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:scroll_button_lock"].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["input:tablet:region_position"].vecValue = Vector2D();
configValues["input:tablet:region_size"].vecValue = Vector2D();
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;
configValues["binds:workspace_center_on"].intValue = 1;
configValues["binds:focus_preferred_method"].intValue = 0;
configValues["binds:ignore_group_lock"].intValue = 0;
configValues["binds:movefocus_cycles_fullscreen"].intValue = 1;
2022-07-26 14:50:21 +02:00
2023-08-23 22:40:19 +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;
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_direction_lock"].intValue = 1;
configValues["gestures:workspace_swipe_direction_lock_threshold"].intValue = 10;
configValues["gestures:workspace_swipe_forever"].intValue = 0;
configValues["gestures:workspace_swipe_numbered"].intValue = 0;
configValues["gestures:workspace_swipe_use_r"].intValue = 0;
2022-07-07 11:52:12 +02:00
configValues["xwayland:use_nearest_neighbor"].intValue = 1;
2023-06-11 21:52:13 +02:00
configValues["xwayland:force_zero_scaling"].intValue = 0;
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;
cfgValues["scroll_button_lock"].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
cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
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();
const std::string CONFIGPATH = getMainConfigPath();
2022-03-19 17:00:52 +01:00
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) {
2023-09-06 12:51:36 +02:00
Debug::log(WARN, "Error at statting config, error {}", errno);
2022-03-19 17:00:52 +01:00
}
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.contains(COMMAND)) {
if (!COMMAND.starts_with("device:") /* devices parsed later */ && !COMMAND.starts_with("plugin:") /* plugins parsed later */) {
if (COMMAND[0] == '$') {
// register a dynamic var
Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE);
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.starts_with("device:")) {
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.starts_with("plugin:")) {
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) {
m_vFailedPluginConfigValues.emplace_back(std::make_pair<>(COMMAND, VALUE));
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) {
Debug::log(WARN, "Error reading value of {}", COMMAND);
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 {}", COMMAND);
2022-03-17 15:53:45 +01:00
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 {}", COMMAND);
2022-03-17 15:53:45 +01:00
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 {}", COMMAND);
2022-09-30 18:03:06 +02:00
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
} catch (...) {
Debug::log(WARN, "Error reading value of {}", COMMAND);
2022-09-30 18:03:06 +02:00
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 {}", COMMAND);
2022-11-26 18:56:43 +01:00
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
break;
}
if (data->m_vColors.size() >= 10) {
Debug::log(WARN, "Error reading value of {}", COMMAND);
2022-11-26 18:56:43 +01:00
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 {}", COMMAND);
2022-11-26 18:56:43 +01:00
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
}
}
if (data->m_vColors.size() == 0) {
Debug::log(WARN, "Error reading value of {}", COMMAND);
2022-11-26 18:56:43 +01:00
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 {}, error {}: {}", PATH, err, strerror(err));
2022-12-01 14:36:07 +01:00
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
}
static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) {
auto args = CVarList(modeline, 0, 's');
auto keyword = args[0];
std::transform(keyword.begin(), keyword.end(), keyword.begin(), ::tolower);
if (keyword != "modeline")
return false;
if (args.size() < 10) {
2023-09-06 12:51:36 +02:00
Debug::log(ERR, "modeline parse error: expected at least 9 arguments, got {}", args.size() - 1);
return false;
}
int argno = 1;
mode.type = DRM_MODE_TYPE_USERDEF;
mode.clock = std::stof(args[argno++]) * 1000;
mode.hdisplay = std::stoi(args[argno++]);
mode.hsync_start = std::stoi(args[argno++]);
mode.hsync_end = std::stoi(args[argno++]);
mode.htotal = std::stoi(args[argno++]);
mode.vdisplay = std::stoi(args[argno++]);
mode.vsync_start = std::stoi(args[argno++]);
mode.vsync_end = std::stoi(args[argno++]);
mode.vtotal = std::stoi(args[argno++]);
mode.vrefresh = mode.clock * 1000.0 * 1000.0 / mode.htotal / mode.vtotal;
static std::unordered_map<std::string, uint32_t> flagsmap = {
{"+hsync", DRM_MODE_FLAG_PHSYNC},
{"-hsync", DRM_MODE_FLAG_NHSYNC},
{"+vsync", DRM_MODE_FLAG_PVSYNC},
{"-vsync", DRM_MODE_FLAG_NVSYNC},
};
for (; argno < static_cast<int>(args.size()); argno++) {
auto key = args[argno];
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
auto it = flagsmap.find(key);
if (it != flagsmap.end())
mode.flags |= it->second;
else
Debug::log(ERR, "invalid flag {} in modeline", it->first);
}
snprintf(mode.name, sizeof(mode.name), "%dx%d@%d", mode.hdisplay, mode.vdisplay, mode.vrefresh / 1000);
return true;
}
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) {
2023-09-06 12:51:36 +02:00
Debug::log(ERR, "invalid transform {} in monitor", TSF);
parseError = "invalid transform";
return;
}
const auto TRANSFORM = (wl_output_transform)TSF;
// 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].starts_with("pref")) {
2022-07-30 22:54:29 +02:00
newrule.resolution = Vector2D();
} else if (ARGS[1].starts_with("highrr")) {
newrule.resolution = Vector2D(-1, -1);
} else if (ARGS[1].starts_with("highres")) {
newrule.resolution = Vector2D(-1, -2);
} else if (parseModeLine(ARGS[1], newrule.drmMode)) {
newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
newrule.refreshRate = newrule.drmMode.vrefresh / 1000;
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].starts_with("auto")) {
newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX);
2022-08-04 11:10:26 +02:00
} 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-08-03 21:06:51 +02:00
}
if (ARGS[3].starts_with("auto")) {
2022-12-14 18:57:18 +01:00
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++;
2023-08-11 17:37:52 +02:00
} else if (ARGS[argno] == "vrr") {
newrule.vrr = std::stoi(ARGS[argno + 1]);
argno++;
} else if (ARGS[argno] == "workspace") {
std::string name = "";
int wsId = getWorkspaceIDFromString(ARGS[argno + 1], name);
SWorkspaceRule wsRule;
wsRule.monitor = newrule.name;
wsRule.workspaceString = ARGS[argno + 1];
wsRule.workspaceName = name;
wsRule.workspaceId = wsId;
m_dWorkspaceRules.emplace_back(wsRule);
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";
}
if (PANIM->second.internalEnabled) {
// speed
if (isNumber(ARGS[2], true)) {
PANIM->second.internalSpeed = std::stof(ARGS[2]);
if (PANIM->second.internalSpeed <= 0) {
parseError = "invalid speed";
PANIM->second.internalSpeed = 1.f;
}
} else {
PANIM->second.internalSpeed = 10.f;
parseError = "invalid speed";
2022-08-07 19:28:46 +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";
PANIM->second.internalBezier = "default";
}
2022-08-07 19:28:46 +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-08-07 19:28:46 +02:00
}
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;
bool nonConsuming = false;
bool transparent = false;
2023-10-17 21:09:54 +02:00
bool ignoreMods = 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;
} else if (arg == 'n') {
nonConsuming = true;
} else if (arg == 't') {
transparent = true;
2023-10-17 21:09:54 +02:00
} else if (arg == 'i') {
ignoreMods = 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)
2023-10-17 21:09:54 +02:00
g_pKeybindManager->addKeybind(
SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
else if (KEY.starts_with("code:") && isNumber(KEY.substr(5)))
g_pKeybindManager->addKeybind(
2023-10-17 21:09:54 +02:00
SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
2022-07-08 09:27:17 +02:00
else
2023-10-17 21:09:54 +02:00
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
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.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" ||
RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "nofullscreenrequest" ||
RULE == "nomaximizerequest" || RULE == "fakefullscreen" || RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" ||
RULE == "maximize" || RULE == "keepaspectratio" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") ||
RULE.starts_with("bordercolor") || RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") ||
2023-10-24 22:28:55 +02:00
RULE.starts_with("center") || RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor";
2022-09-06 11:57:11 +02:00
}
2023-01-25 16:34:13 +01:00
bool layerRuleValid(const std::string& RULE) {
return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray");
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: {}", RULE);
2022-09-06 11:57:11 +02:00
parseError = "Invalid rule found: " + RULE;
return;
}
2022-03-24 18:22:01 +01:00
if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
m_dWindowRules.push_front({RULE, VALUE});
else
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: {}", RULE);
2023-01-25 16:34:13 +01:00
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 = removeBeginEndSpacesTabs(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") {
Debug::log(ERR, "Invalid rulev2 found: {}", RULE);
2022-09-06 11:57:11 +02:00
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:");
2023-08-02 13:21:38 +02:00
const auto WORKSPACEPOS = VALUE.find("workspace:");
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 &&
2023-08-02 13:21:38 +02:00
PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos) {
Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
2022-09-06 11:57:11 +02:00
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;
2023-08-02 13:21:38 +02:00
if (WORKSPACEPOS > pos && WORKSPACEPOS < 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;
};
2023-08-02 13:21:38 +02:00
if (CLASSPOS != std::string::npos)
2022-09-06 11:57:11 +02:00
rule.szClass = extract(CLASSPOS + 6);
2023-08-02 13:21:38 +02:00
if (TITLEPOS != std::string::npos)
2022-09-06 11:57:11 +02:00
rule.szTitle = extract(TITLEPOS + 6);
2023-08-02 13:21:38 +02:00
if (X11POS != std::string::npos)
rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
2023-08-02 13:21:38 +02:00
if (FLOATPOS != std::string::npos)
rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
2023-08-02 13:21:38 +02:00
if (FULLSCREENPOS != std::string::npos)
rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
2023-08-02 13:21:38 +02:00
if (PINNEDPOS != std::string::npos)
rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
2023-08-02 13:21:38 +02:00
if (WORKSPACEPOS != std::string::npos)
rule.szWorkspace = extract(WORKSPACEPOS + 10);
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 {
2023-08-02 13:21:38 +02:00
if (!rule.szClass.empty() && rule.szClass != other.szClass)
2022-11-03 20:52:43 +01:00
return false;
2023-08-02 13:21:38 +02:00
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
2022-11-03 20:52:43 +01:00
return false;
2023-08-02 13:21:38 +02:00
if (rule.bX11 != -1 && rule.bX11 != other.bX11)
2022-11-03 20:52:43 +01:00
return false;
2023-08-02 13:21:38 +02:00
if (rule.bFloating != -1 && rule.bFloating != other.bFloating)
2022-11-03 20:52:43 +01:00
return false;
2023-08-02 13:21:38 +02:00
if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen)
return false;
2023-08-02 13:21:38 +02:00
if (rule.bPinned != -1 && rule.bPinned != other.bPinned)
return false;
if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
return false;
2022-11-03 20:52:43 +01:00
return true;
}
});
return;
}
if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
m_dWindowRules.push_front(rule);
else
m_dWindowRules.push_back(rule);
2022-03-24 18:22:01 +01:00
}
void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
const bool BYADDRESS = name.starts_with("address:");
2023-02-25 18:39:26 +01:00
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) {
if (std::format("0x{:x}", (uintptr_t)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) {
if (value.starts_with("remove,")) {
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
}
void CConfigManager::handleWorkspaceRules(const std::string& command, const std::string& value) {
// This can either be the monitor or the workspace identifier
const auto FIRST_DELIM = value.find_first_of(',');
std::string name = "";
auto first_ident = removeBeginEndSpacesTabs(value.substr(0, FIRST_DELIM));
int id = getWorkspaceIDFromString(first_ident, name);
auto rules = value.substr(FIRST_DELIM + 1);
SWorkspaceRule wsRule;
wsRule.workspaceString = first_ident;
if (id == WORKSPACE_INVALID) {
// it could be the monitor. If so, second value MUST be
// the workspace.
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
id = getWorkspaceIDFromString(wsIdent, name);
if (id == WORKSPACE_INVALID) {
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
parseError = "Invalid workspace identifier found: " + wsIdent;
return;
}
wsRule.monitor = first_ident;
wsRule.workspaceString = wsIdent;
wsRule.isDefault = true; // backwards compat
rules = value.substr(WORKSPACE_DELIM + 1);
}
const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();
auto assignRule = [&](std::string rule) {
size_t delim = std::string::npos;
if ((delim = rule.find("gapsin:")) != std::string::npos)
wsRule.gapsIn = std::stoi(rule.substr(delim + 7));
else if ((delim = rule.find("gapsout:")) != std::string::npos)
wsRule.gapsOut = std::stoi(rule.substr(delim + 8));
else if ((delim = rule.find("bordersize:")) != std::string::npos)
wsRule.borderSize = std::stoi(rule.substr(delim + 11));
else if ((delim = rule.find("border:")) != std::string::npos)
wsRule.border = configStringToInt(rule.substr(delim + 7));
else if ((delim = rule.find("shadow:")) != std::string::npos)
wsRule.shadow = configStringToInt(rule.substr(delim + 7));
else if ((delim = rule.find("rounding:")) != std::string::npos)
wsRule.rounding = configStringToInt(rule.substr(delim + 9));
else if ((delim = rule.find("decorate:")) != std::string::npos)
wsRule.decorate = configStringToInt(rule.substr(delim + 9));
else if ((delim = rule.find("monitor:")) != std::string::npos)
wsRule.monitor = rule.substr(delim + 8);
else if ((delim = rule.find("default:")) != std::string::npos)
wsRule.isDefault = configStringToInt(rule.substr(delim + 8));
else if ((delim = rule.find("persistent:")) != std::string::npos)
wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos)
wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen));
};
size_t pos = 0;
std::string rule;
while ((pos = rules.find(',')) != std::string::npos) {
rule = rules.substr(0, pos);
assignRule(rule);
rules.erase(0, pos + 1);
}
assignRule(rules); // match remaining rule
2022-03-20 16:01:47 +01:00
wsRule.workspaceId = id;
wsRule.workspaceName = name;
2023-05-12 02:15:32 +02:00
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { return other.workspaceString == wsRule.workspaceString; });
if (IT == m_dWorkspaceRules.end())
m_dWorkspaceRules.emplace_back(wsRule);
else
*IT = wsRule;
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;
}
std::unique_ptr<glob_t, void (*)(glob_t*)> glob_buf{new glob_t, [](glob_t* g) { globfree(g); }};
memset(glob_buf.get(), 0, sizeof(glob_t));
2022-07-06 15:05:23 +02:00
if (auto r = glob(absolutePath(rawpath, configCurrentPath).c_str(), GLOB_TILDE, nullptr, glob_buf.get()); r != 0) {
parseError = std::format("source= globbing error: {}", r == GLOB_NOMATCH ? "found no match" : GLOB_ABORTED ? "read error" : "out of memory");
Debug::log(ERR, "{}", parseError);
2022-05-16 10:09:20 +02:00
return;
}
for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
auto value = absolutePath(glob_buf->gl_pathv[i], 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);
2022-05-16 10:09:20 +02:00
struct stat fileStat;
int err = stat(value.c_str(), &fileStat);
if (err != 0) {
Debug::log(WARN, "Error at ticking config at {}, error {}: {}", value, err, strerror(err));
return;
}
configModifyTimes[value] = fileStat.st_mtime;
std::ifstream ifs;
ifs.open(value);
2022-05-16 10:09:20 +02:00
std::string line = "";
int linenum = 1;
if (ifs.is_open()) {
auto configCurrentPathBackup = configCurrentPath;
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, "{}", line.c_str());
parseError += "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): Line parsing error.";
}
if (parseError != "" && !parseError.starts_with("Config error at line")) {
parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError;
}
++linenum;
2022-05-16 10:09:20 +02:00
}
ifs.close();
configCurrentPath = configCurrentPathBackup;
2022-05-16 10:09:20 +02:00
}
}
}
2022-09-12 21:05:52 +02:00
void CConfigManager::handleBindWS(const std::string& command, const std::string& value) {
2023-05-05 16:41:25 +02:00
parseError = "bindws has been deprecated in favor of workspace rules, see the wiki -> workspace rules";
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);
2023-03-05 14:15:12 +01:00
}
2023-03-05 14:12:01 +01:00
}
void CConfigManager::handlePlugin(const std::string& command, const std::string& path) {
if (std::find(m_vDeclaredPlugins.begin(), m_vDeclaredPlugins.end(), path) != m_vDeclaredPlugins.end()) {
parseError = "plugin '" + path + "' declared twice";
return;
}
m_vDeclaredPlugins.push_back(path);
}
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.starts_with("bind"))
handleBind(COMMAND, VALUE);
else if (COMMAND == "unbind")
handleUnbind(COMMAND, VALUE);
else if (COMMAND == "workspace")
handleWorkspaceRules(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);
else if (COMMAND == "plugin")
handlePlugin(COMMAND, VALUE);
else if (COMMAND.starts_with("env"))
2023-03-05 14:12:01 +01:00
handleEnv(COMMAND, VALUE);
else {
// try config
const auto IT = std::find_if(pluginKeywords.begin(), pluginKeywords.end(), [&](const auto& other) { return other.name == COMMAND; });
if (IT != pluginKeywords.end()) {
IT->fn(COMMAND, VALUE);
} else {
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.starts_with("dwindle:") || COMMAND.starts_with("master:")) {
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) {
if (STRAFTERDOLLAR.starts_with(var)) {
2022-05-16 09:38:42 +02:00
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.starts_with(var)) {
2023-03-05 15:54:26 +01:00
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() {
EMIT_HOOK_EVENT("preConfigReload", nullptr);
2022-03-17 15:53:45 +01:00
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();
m_dWorkspaceRules.clear();
2022-07-28 13:28:43 +02:00
setDefaultAnimationVars(); // reset anims
m_vDeclaredPlugins.clear();
2023-05-04 19:28:45 +02:00
m_dLayerRules.clear();
m_vFailedPluginConfigValues.clear();
2022-03-17 16:56:33 +01:00
2022-05-16 10:09:20 +02:00
// paths
configPaths.clear();
std::string mainConfigPath = getMainConfigPath();
Debug::log(LOG, "Using config: {}", mainConfigPath);
configPaths.push_back(mainConfigPath);
std::string configPath = mainConfigPath.substr(0, mainConfigPath.find_last_of('/'));
// find_last_of never returns npos since main_config at least has /hypr/
if (!std::filesystem::is_directory(configPath)) {
Debug::log(WARN, "Creating config home directory");
try {
std::filesystem::create_directories(configPath);
} catch (...) {
parseError = "Broken config file! (Could not create config directory)";
return;
}
}
2022-05-16 10:09:20 +02:00
if (!std::filesystem::exists(mainConfigPath)) {
Debug::log(WARN, "No config file found; attempting to generate.");
std::ofstream ofs;
ofs.open(mainConfigPath, std::ios::trunc);
ofs << AUTOCONFIG;
ofs.close();
}
2022-09-25 20:07:48 +02:00
2022-03-17 15:53:45 +01:00
std::ifstream ifs;
ifs.open(mainConfigPath);
2022-03-17 15:53:45 +01:00
if (!ifs.good()) {
Debug::log(WARN, "Config reading error. Attempting to generate, backing up old one if exists");
2022-03-17 15:53:45 +01:00
ifs.close();
if (std::filesystem::exists(mainConfigPath))
std::filesystem::rename(mainConfigPath, mainConfigPath + ".backup");
// Create default config
std::ofstream ofs;
ofs.open(mainConfigPath, std::ios::trunc);
ofs << AUTOCONFIG;
ofs.close();
// Try to re-open
ifs.open(mainConfigPath);
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 {
2023-07-10 13:10:30 +02:00
configCurrentPath = mainConfigPath;
2022-03-17 15:53:45 +01:00
parseLine(line);
} catch (...) {
Debug::log(ERR, "Error reading line from config. Line:");
Debug::log(NONE, "{}", line);
2022-03-17 15:53:45 +01:00
parseError += "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): Line parsing error.";
2022-03-17 15:53:45 +01:00
}
if (parseError != "" && !parseError.starts_with("Config error at line")) {
parseError = "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): " + 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 != "" && !configValues["debug:suppress_errors"].intValue)
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: " + mainConfigPath + " )\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
// Updates dynamic window and workspace rules
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped)
continue;
2023-07-01 16:30:36 +02:00
w->updateDynamicRules();
w->updateSpecialRenderData();
}
2023-07-01 16:30:36 +02:00
// Update window border colors
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
2023-07-01 16:30:36 +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;
if (Debug::disableStdout && isFirstLaunch)
Debug::log(LOG, "Disabling stdout logs! Check the log for further logs.");
2023-03-24 20:37:37 +01:00
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());
g_pCompositor->scheduleFrameForMonitor(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;
// update plugins
handlePluginLoads();
2023-07-10 13:54:06 +02:00
EMIT_HOOK_EVENT("configReloaded", nullptr);
2022-03-17 15:53:45 +01:00
}
void CConfigManager::tick() {
std::string CONFIGPATH = getMainConfigPath();
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 {}, error {}: {}", cf, 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;
}
SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback) {
2022-06-30 21:26:00 +02:00
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()) {
if (fallback.empty()) {
Debug::log(ERR, "getConfigValueSafeDevice: No device config for {} found???", dev);
return SConfigValue();
}
return configValues[fallback];
2022-06-30 21:26:00 +02:00
}
const SConfigValue DEVICECONFIG = it->second[val];
2022-06-30 21:26:00 +02:00
if (!DEVICECONFIG.set && !fallback.empty()) {
return configValues[fallback];
2022-06-30 21:38:06 +02:00
}
return DEVICECONFIG;
2022-06-30 21:26:00 +02:00
}
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;
}
Vector2D CConfigManager::getVec(const std::string& v) {
return getConfigValueSafe(v).vecValue;
}
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
int CConfigManager::getDeviceInt(const std::string& dev, const std::string& v, const std::string& fallback) {
return getConfigValueSafeDevice(dev, v, fallback).intValue;
2022-06-30 21:26:00 +02:00
}
float CConfigManager::getDeviceFloat(const std::string& dev, const std::string& v, const std::string& fallback) {
return getConfigValueSafeDevice(dev, v, fallback).floatValue;
2022-06-30 21:26:00 +02:00
}
Vector2D CConfigManager::getDeviceVec(const std::string& dev, const std::string& v, const std::string& fallback) {
return getConfigValueSafeDevice(dev, v, fallback).vecValue;
}
std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) {
auto VAL = getConfigValueSafeDevice(dev, v, fallback).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::setVec(const std::string& v, Vector2D val) {
configValues[v].vecValue = 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.starts_with("desc:") &&
(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;
Debug::log(WARN, "No rule found for {}, trying to use the first.", name);
2022-03-19 17:00:52 +01:00
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.");
return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-INT32_MAX, -INT32_MAX), .scale = -1}; // 0, 0 is preferred and -1, -1 is auto
2022-03-24 18:22:01 +01:00
}
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) {
const auto WORKSPACEIDSTR = std::to_string(pWorkspace->m_iID);
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) {
return other.workspaceName == pWorkspace->m_szName /* name matches */
|| (pWorkspace->m_bIsSpecialWorkspace && other.workspaceName.starts_with("special:") &&
other.workspaceName.substr(8) == pWorkspace->m_szName) /* special and special:name */
|| (pWorkspace->m_iID > 0 && WORKSPACEIDSTR == other.workspaceName); /* id matches and workspace is numerical */
});
if (IT == m_dWorkspaceRules.end())
return SWorkspaceRule{};
return *IT;
}
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 {} (title: {})", appidclass, title);
// since some rules will be applied later, we need to store some flags
bool hasFloating = pWindow->m_bIsFloating;
bool hasFullscreen = pWindow->m_bIsFullscreen;
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.starts_with("title:")) {
2022-09-06 11:57:11 +02:00
// 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 {}", rule.szValue);
2022-09-06 11:57:11 +02:00
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 (hasFloating != rule.bFloating)
continue;
}
if (rule.bFullscreen != -1) {
if (hasFullscreen != rule.bFullscreen)
continue;
}
if (rule.bPinned != -1) {
if (pWindow->m_bPinned != rule.bPinned)
continue;
}
2023-08-02 13:21:38 +02:00
if (!rule.szWorkspace.empty()) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (!PWORKSPACE)
continue;
if (rule.szWorkspace.starts_with("name:")) {
2023-08-02 13:21:38 +02:00
if (PWORKSPACE->m_szName != rule.szWorkspace.substr(5))
continue;
} else {
// number
if (!isNumber(rule.szWorkspace))
throw std::runtime_error("szWorkspace not name: or number");
const int64_t ID = std::stoll(rule.szWorkspace);
if (PWORKSPACE->m_iID != ID)
continue;
}
}
} catch (std::exception& e) {
Debug::log(ERR, "Regex error at {} ({})", rule.szValue, e.what());
2022-09-06 11:57:11 +02:00
continue;
}
2022-03-24 18:22:01 +01:00
}
// applies. Read the rule and behave accordingly
Debug::log(LOG, "Window rule {} -> {} matched {}", rule.szRule, rule.szValue, pWindow);
2022-03-24 18:22:01 +01:00
returns.push_back(rule);
if (rule.szRule == "float")
hasFloating = true;
else if (rule.szRule == "fullscreen")
hasFullscreen = true;
2022-03-24 18:22:01 +01:00
}
2023-04-18 12:48:56 +02:00
std::vector<uint64_t> PIDs = {(uint64_t)pWindow->getPID()};
while (getPPIDof(PIDs.back()) > 10)
PIDs.push_back(getPPIDof(PIDs.back()));
bool anyExecFound = false;
2022-11-10 14:39:23 +01:00
for (auto& er : execRequestedRules) {
2023-04-18 12:48:56 +02:00
if (std::ranges::any_of(PIDs, [&](const auto& pid) { return pid == er.iPid; })) {
2022-11-10 14:39:23 +01:00
returns.push_back({er.szRule, "execRule"});
anyExecFound = true;
}
}
if (anyExecFound) // remove exec rules to unclog searches in the future, why have the garbage here.
2023-04-18 12:48:56 +02:00
execRequestedRules.erase(std::remove_if(execRequestedRules.begin(), execRequestedRules.end(),
[&](const SExecRequestedRule& other) { return std::ranges::any_of(PIDs, [&](const auto& pid) { return pid == other.iPid; }); }));
2022-11-10 14:39:23 +01:00
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) {
if (lr.targetNamespace.starts_with("address:0x")) {
if (std::format("address:0x{:x}", (uintptr_t)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
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) {
if (!m->output || m->isUnsafeFallback)
2023-03-15 16:11:41 +01:00
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-04-19 19:01:23 +02:00
m_bWantsMonitorReload = false;
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
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) {
if (val.starts_with("device:")) {
const auto DEVICE = val.substr(7, val.find_last_of(':') - 7);
const auto CONFIGVAR = val.substr(val.find_last_of(':') + 1);
const auto DEVICECONF = deviceConfigs.find(DEVICE);
if (DEVICECONF == deviceConfigs.end())
return nullptr;
const auto IT = DEVICECONF->second.find(CONFIGVAR);
if (IT == DEVICECONF->second.end())
return nullptr;
2022-08-11 21:16:38 +02:00
return &IT->second;
} else if (val.starts_with("plugin:")) {
for (auto& [pl, pMap] : pluginConfigs) {
const auto IT = pMap->find(val);
if (IT != pMap->end())
return &IT->second;
}
2022-08-11 21:16:38 +02:00
return nullptr;
}
2022-08-11 21:16:38 +02:00
const auto IT = configValues.find(val);
if (IT == configValues.end())
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(), ' ', '-');
return deviceConfigs.contains(copy);
2022-06-30 21:26:00 +02:00
}
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) {
if (!rm->output || rm->isUnsafeFallback)
2023-03-16 15:03:40 +01:00
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)
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-08-11 17:37:52 +02:00
const auto USEVRR = m->activeMonitorRule.vrr.has_value() ? m->activeMonitorRule.vrr.value() : *PVRR;
if (USEVRR == 0) {
2023-02-14 18:08:42 +01:00
if (m->vrrActive) {
2022-10-22 22:45:17 +02:00
wlr_output_enable_adaptive_sync(m->output, 0);
if (!wlr_output_commit(m->output))
2023-09-06 12:51:36 +02:00
Debug::log(ERR, "Couldn't commit output {} 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;
2023-08-11 17:37:52 +02:00
} else if (USEVRR == 1) {
2023-02-14 18:08:42 +01:00
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)) {
2023-09-06 12:51:36 +02:00
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
2023-02-14 18:08:42 +01:00
wlr_output_enable_adaptive_sync(m->output, 0);
}
if (!wlr_output_commit(m->output))
2023-09-06 12:51:36 +02:00
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
2023-02-14 18:08:42 +01:00
}
m->vrrActive = true;
return;
2023-08-11 17:37:52 +02:00
} else if (USEVRR == 2) {
2023-02-14 18:08:42 +01:00
/* 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
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) {
2023-02-14 18:08:42 +01:00
wlr_output_enable_adaptive_sync(m->output, 1);
if (!wlr_output_test(m->output)) {
2023-09-06 12:51:36 +02:00
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
2023-02-14 18:08:42 +01:00
wlr_output_enable_adaptive_sync(m->output, 0);
}
2022-10-22 22:45:17 +02:00
if (!wlr_output_commit(m->output))
2023-09-06 12:51:36 +02:00
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) {
2023-02-14 18:08:42 +01:00
wlr_output_enable_adaptive_sync(m->output, 0);
if (!wlr_output_commit(m->output))
2023-09-06 12:51:36 +02:00
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
2023-02-14 18:08:42 +01:00
}
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) {
auto monitor = getBoundMonitorStringForWS(wsname);
if (monitor.substr(0, 5) == "desc:")
return g_pCompositor->getMonitorFromDesc(monitor.substr(5));
else
return g_pCompositor->getMonitorFromName(monitor);
2022-09-12 21:05:52 +02:00
}
2022-11-10 14:39:23 +01:00
std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) {
2023-05-05 16:41:25 +02:00
for (auto& wr : m_dWorkspaceRules) {
const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName;
2022-12-09 18:17:02 +01:00
if (WSNAME == wsname) {
2023-05-05 16:41:25 +02:00
return wr.monitor;
2022-12-09 18:17:02 +01:00
}
}
return "";
}
const std::deque<SWorkspaceRule>& CConfigManager::getAllWorkspaceRules() {
return m_dWorkspaceRules;
}
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
void CConfigManager::handlePluginLoads() {
if (g_pPluginSystem == nullptr)
return;
bool pluginsChanged = false;
auto failedPlugins = g_pPluginSystem->updateConfigPlugins(m_vDeclaredPlugins, pluginsChanged);
if (!failedPlugins.empty()) {
std::stringstream error;
error << "Failed to load the following plugins:";
for (auto path : failedPlugins) {
error << "\n" << path;
}
g_pHyprError->queueCreate(error.str(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
}
if (pluginsChanged) {
g_pHyprError->destroy();
m_bForceReload = true;
tick();
}
}
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;
if (const auto IT = std::find_if(m_vFailedPluginConfigValues.begin(), m_vFailedPluginConfigValues.end(), [&](const auto& other) { return other.first == name; });
IT != m_vFailedPluginConfigValues.end()) {
configSetValueSafe(IT->first, IT->second);
}
}
void CConfigManager::addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string&, const std::string&)> fn) {
pluginKeywords.emplace_back(SPluginKeyword{handle, name, fn});
}
void CConfigManager::removePluginConfig(HANDLE handle) {
std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; });
std::erase_if(pluginKeywords, [&](const auto& other) { return other.handle == handle; });
}
std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {
2023-07-10 07:53:03 +02:00
for (auto other = m_dWorkspaceRules.begin(); other != m_dWorkspaceRules.end(); ++other) {
if (other->isDefault) {
if (other->monitor == name)
return other->workspaceString;
if (other->monitor.substr(0, 5) == "desc:") {
auto monitor = g_pCompositor->getMonitorFromDesc(other->monitor.substr(5));
if (monitor && monitor->szName == name)
return other->workspaceString;
}
}
2023-07-10 07:53:03 +02:00
}
return "";
}