Hyprland/src/config/ConfigManager.hpp

311 lines
16 KiB
C++

#pragma once
#define CONFIG_MANAGER_H
#include <map>
#include "../debug/Log.hpp"
#include <unordered_map>
#include "../defines.hpp"
#include <variant>
#include <vector>
#include <deque>
#include <algorithm>
#include <regex>
#include <optional>
#include <functional>
#include <xf86drmMode.h>
#include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp"
#include "../helpers/varlist/VarList.hpp"
#include "../desktop/Window.hpp"
#include "../desktop/LayerSurface.hpp"
#include "defaultConfig.hpp"
#include "ConfigDataValues.hpp"
#include <hyprlang.hpp>
#define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
#define HANDLE void*
struct SWorkspaceRule {
std::string monitor = "";
std::string workspaceString = "";
std::string workspaceName = "";
WORKSPACEID workspaceId = -1;
bool isDefault = false;
bool isPersistent = false;
std::optional<CCssGapData> gapsIn;
std::optional<CCssGapData> gapsOut;
std::optional<int64_t> borderSize;
std::optional<bool> decorate;
std::optional<bool> noRounding;
std::optional<bool> noBorder;
std::optional<bool> noShadow;
std::optional<std::string> onCreatedEmptyRunCmd;
std::optional<std::string> defaultName;
std::map<std::string, std::string> layoutopts;
};
struct SMonitorAdditionalReservedArea {
int top = 0;
int bottom = 0;
int left = 0;
int right = 0;
};
struct SAnimationPropertyConfig {
bool overridden = true;
std::string internalBezier = "";
std::string internalStyle = "";
float internalSpeed = 0.f;
int internalEnabled = -1;
SAnimationPropertyConfig* pValues = nullptr;
SAnimationPropertyConfig* pParentAnimation = nullptr;
};
struct SPluginKeyword {
HANDLE handle = 0;
std::string name = "";
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
};
struct SPluginVariable {
HANDLE handle = 0;
std::string name = "";
};
struct SExecRequestedRule {
std::string szRule = "";
uint64_t iPid = 0;
};
enum eConfigOptionType : uint16_t {
CONFIG_OPTION_BOOL = 0,
CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/
CONFIG_OPTION_FLOAT = 2,
CONFIG_OPTION_STRING_SHORT = 3, /* e.g. "auto" */
CONFIG_OPTION_STRING_LONG = 4, /* e.g. a command */
CONFIG_OPTION_COLOR = 5,
CONFIG_OPTION_CHOICE = 6, /* e.g. "one", "two", "three" */
CONFIG_OPTION_GRADIENT = 7,
CONFIG_OPTION_VECTOR = 8,
};
enum eConfigOptionFlags : uint32_t {
CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0),
};
struct SConfigOptionDescription {
struct SBoolData {
bool value = false;
};
struct SRangeData {
int value = 0, min = 0, max = 2;
};
struct SFloatData {
float value = 0, min = 0, max = 100;
};
struct SStringData {
std::string value;
};
struct SColorData {
CColor color;
};
struct SChoiceData {
int firstIndex = 0;
std::string choices; // comma-separated
};
struct SGradientData {
std::string gradient;
};
struct SVectorData {
Vector2D vec, min, max;
};
std::string value; // e.g. general:gaps_in
std::string description;
std::string specialCategory; // if value is special (e.g. device:abc) value will be abc and special device
bool specialKey = false;
eConfigOptionType type = CONFIG_OPTION_BOOL;
uint32_t flags = 0; // eConfigOptionFlags
std::string jsonify() const;
//
std::variant<SBoolData, SRangeData, SFloatData, SStringData, SColorData, SChoiceData, SGradientData, SVectorData> data;
};
class CConfigManager {
public:
CConfigManager();
void tick();
void init();
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
bool deviceConfigExists(const std::string&);
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
bool shouldBlurLS(const std::string&);
void* const* getConfigValuePtr(const std::string&);
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getMainConfigPath();
const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const SP<CMonitor>);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&);
CMonitor* getBoundMonitorForWS(const std::string&);
std::string getBoundMonitorStringForWS(const std::string&);
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
std::vector<SWindowRule> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
std::vector<SLayerRule> getMatchingRules(PHLLS);
const std::vector<SConfigOptionDescription>& getAllDescriptions();
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value);
void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {});
void removePluginConfig(HANDLE handle);
// no-op when done.
void dispatchExecOnce();
void dispatchExecShutdown();
void performMonitorReload();
void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&);
void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr);
std::string parseKeyword(const std::string&, const std::string&);
void addParseError(const std::string&);
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
void addExecRule(const SExecRequestedRule&);
void handlePluginLoads();
std::string getErrors();
// keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(PHLWINDOW)>> mbWindowProperties = {
{"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
{"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
private:
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
std::vector<std::string> m_vDeclaredPlugins;
std::vector<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> pluginVariables;
bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules;
std::deque<SWorkspaceRule> m_dWorkspaceRules;
std::deque<SWindowRule> m_dWindowRules;
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false;
std::deque<std::string> firstExecRequests;
std::deque<std::string> finalExecRequests;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = "";
// internal methods
void setAnimForChildren(SAnimationPropertyConfig* const);
void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig();
static std::optional<std::string> generateConfig(std::string configPath);
static std::optional<std::string> verifyConfigExists();
void postConfigReload(const Hyprlang::CParseResult& result);
void reload();
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
};
inline std::unique_ptr<CConfigManager> g_pConfigManager;