summaryrefslogtreecommitdiff
path: root/src/config/lua/ConfigManager.hpp
blob: 773877583379ef5c039a427a97061fe24b1d3995 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#pragma once

#include <hyprutils/animation/AnimationConfig.hpp>

#include <vector>
#include <string>
#include <optional>
#include <chrono>
#include <string_view>
#include <unordered_map>

#include "../../helpers/memory/Memory.hpp"
#include "../ConfigManager.hpp"
#include "../../managers/eventLoop/EventLoopTimer.hpp"

#include "./types/LuaConfigValue.hpp"
#include "./LuaEventHandler.hpp"

#include "../../desktop/rule/windowRule/WindowRule.hpp"
#include "../../desktop/rule/layerRule/LayerRule.hpp"

#include "../../SharedDefs.hpp"
#include "../../managers/KeybindManager.hpp"
#include "../shared/ConfigErrors.hpp"

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

namespace Config::Supplementary {
    struct SConfigOptionDescription;
};

namespace Config::Lua {
    class CConfigManager;
    class CConfigManagerPluginLuaTestAccessor;
}

namespace Config::Lua::Bindings {
    void registerBindings(lua_State* L, CConfigManager* mgr);
}

namespace Config::Lua {

    class CConfigManager : public Config::IConfigManager {
      public:
        CConfigManager();

        virtual eConfigManagerType               type() override;

        virtual void                             init() override;
        virtual void                             reload() override;
        virtual std::string                      verify() override;

        virtual int                              getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "") override;
        virtual float                            getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "") override;
        virtual Vector2D                         getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "") override;
        virtual std::string                      getDeviceString(const std::string&, const std::string&, const std::string& fallback = "") override;
        virtual bool                             deviceConfigExplicitlySet(const std::string&, const std::string&) override;
        virtual bool                             deviceConfigExists(const std::string&) override;

        virtual SConfigOptionReply               getConfigValue(const std::string&) override;

        virtual std::string                      getMainConfigPath() override;
        virtual std::string                      getErrors() override;
        virtual std::string                      getConfigString() override;
        virtual std::string                      currentConfigPath() override;
        virtual const std::vector<std::string>&  getConfigPaths() override;

        virtual std::expected<void, std::string> generateDefaultConfig(const std::filesystem::path&, bool safeMode) override;

        virtual void                             handlePluginLoads() override;
        virtual bool                             configVerifPassed() override;

        virtual std::expected<void, std::string> registerPluginValue(void* handle, SP<Config::Values::IValue> value) override;
        virtual void                             onPluginUnload(void* handle) override;

        int                                      invokePluginLuaFunctionByID(uint64_t id, lua_State* L);

        std::expected<void, std::string>         registerPluginLuaFunction(void* handle, const std::string& namespace_, const std::string& name, PLUGIN_LUA_FN fn);
        std::expected<void, std::string>         unregisterPluginLuaFunction(void* handle, const std::string& namespace_, const std::string& name);

        void                                     addError(std::string&& str);
        void                                     addEvalIssue(const Config::SConfigError& err);

        void                                     registerLuaRef(int ref);
        void                                     callLuaFn(int ref);

        // execute an arbitrary lua string on the current state.
        std::optional<std::string> eval(const std::string& code);

        int                        guardedPCall(int nargs, int nresults, int errfunc, int timeoutMs, std::string_view context);

        static CConfigManager*     fromLuaState(lua_State* L);

        static constexpr int       LUA_WATCHDOG_INSTRUCTION_INTERVAL = 10000;
        static constexpr int       LUA_TIMEOUT_CONFIG_RELOAD_MS      = 1500;
        static constexpr int       LUA_TIMEOUT_EVENT_CALLBACK_MS     = 50;
        static constexpr int       LUA_TIMEOUT_KEYBIND_CALLBACK_MS   = 100;
        static constexpr int       LUA_TIMEOUT_TIMER_CALLBACK_MS     = 50;
        static constexpr int       LUA_TIMEOUT_EVAL_MS               = 250;
        static constexpr int       LUA_TIMEOUT_DISPATCH_MS           = 100;

        bool                       isFirstLaunch() const;
        bool                       isDynamicParse() const;

        std::string                m_currentSubmap;
        std::string                m_currentSubmapReset;

        UP<CLuaEventHandler>       m_eventHandler;

        struct SLuaTimer {
            SP<CEventLoopTimer> timer;
            int                 luaRef = LUA_NOREF; // registry ref to the lua callback
        };
        std::vector<SLuaTimer>                               m_luaTimers;

        std::vector<std::string>                             m_registeredPlugins;

        std::unordered_map<std::string, UP<ILuaConfigValue>> m_configValues;

        struct SDeviceConfig {
            SDeviceConfig();

            std::unordered_map<std::string, UP<ILuaConfigValue>> values;
        };

        std::unordered_map<std::string, SDeviceConfig> m_deviceConfigs;
        std::vector<std::string>                       m_errors, m_configPaths;
        std::vector<Config::SConfigError>              m_evalIssues;

        // named window/layer rules for merge-on-redeclaration
        std::unordered_map<std::string, SP<Desktop::Rule::CWindowRule>> m_luaWindowRules;
        std::unordered_map<std::string, SP<Desktop::Rule::CLayerRule>>  m_luaLayerRules;

      private:
        void                                  reinitLuaState();
        void                                  postConfigReload();
        void                                  registerValue(const char* name, ILuaConfigValue* val);
        void                                  cleanTimers();
        void                                  clearHeldLuaRefs();
        std::string                           luaConfigValueName(const std::string& s);
        std::expected<void, std::string>      registerPluginLuaFunctionInState(uint64_t id, const std::string& namespace_, const std::string& name);
        std::expected<void, std::string>      unregisterPluginLuaFunctionInState(const std::string& namespace_, const std::string& name);
        void                                  erasePluginLuaFunction(uint64_t id);
        void                                  reregisterLuaPluginFns();

        static void                           watchdogHook(lua_State* L, lua_Debug* ar);

        lua_State*                            m_lua = nullptr;

        bool                                  m_lastConfigVerificationWasSuccessful = true;
        bool                                  m_isFirstLaunch                       = true;
        bool                                  m_manualCrashInitiated                = false;
        bool                                  m_watchdogActive                      = false;
        bool                                  m_isParsingConfig                     = false;
        bool                                  m_isEvaluating                        = false;

        std::chrono::steady_clock::time_point m_watchdogDeadline;
        std::string                           m_watchdogContext;

        std::string                           m_mainConfigPath;

        std::vector<int>                      m_heldLuaRefs;

        // this is here for legacy reasons.
        std::unordered_map<std::string, const void*> m_configPtrMap;

        // this is here for plugin reasons.
        std::unordered_map<void* /* HANDLE */, std::vector<std::string>> m_pluginValues;

        struct SPluginLuaFunction {
            uint64_t              id     = 0;
            void*                 handle = nullptr;
            std::string           namespace_;
            std::string           name;
            Config::PLUGIN_LUA_FN fn = nullptr;
        };
        std::vector<SPluginLuaFunction> m_pluginLuaFunctions;

        ILuaConfigValue*                findDeviceValue(const std::string& dev, const std::string& field);

        friend class CConfigManagerPluginLuaTestAccessor;
    };

    WP<CConfigManager> mgr();
}