From d8f79d7678f428738f3173020109bd7b7fbd0840 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 24 Jan 2025 20:30:12 +0000 Subject: [PATCH] core: add --verify-config to verify the config with Hyprland fixes #9135 --- src/Compositor.cpp | 18 ++++++++++++++++-- src/Compositor.hpp | 11 ++++++----- src/config/ConfigManager.cpp | 30 +++++++++++++++++++++++------- src/config/ConfigManager.hpp | 8 +++++--- src/main.cpp | 17 ++++++++++++----- src/managers/AnimationManager.cpp | 3 ++- src/managers/KeybindManager.cpp | 7 +++++-- 7 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index cb0665e593a..ab9c16f7f04 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" @@ -162,7 +163,10 @@ void CCompositor::restoreNofile() { Debug::log(ERR, "Failed restoring NOFILE limits"); } -CCompositor::CCompositor() : m_iHyprlandPID(getpid()) { +CCompositor::CCompositor(bool onlyConfig) : m_bOnlyConfigVerification(onlyConfig), m_iHyprlandPID(getpid()) { + if (onlyConfig) + return; + m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; if (m_szHyprTempDataRoot.starts_with("/hypr")) { @@ -226,7 +230,7 @@ CCompositor::CCompositor() : m_iHyprlandPID(getpid()) { } CCompositor::~CCompositor() { - if (!m_bIsShuttingDown) + if (!m_bIsShuttingDown && !m_bOnlyConfigVerification) cleanup(); } @@ -262,6 +266,16 @@ static bool filterGlobals(const wl_client* client, const wl_global* global, void // void CCompositor::initServer(std::string socketName, int socketFd) { + if (m_bOnlyConfigVerification) { + g_pHookSystem = makeUnique(); + g_pKeybindManager = makeUnique(); + g_pAnimationManager = makeUnique(); + g_pConfigManager = makeUnique(); + + std::println("\n\n======== Config parsing result:\n\n{}", g_pConfigManager->verify()); + return; + } + m_sWLDisplay = wl_display_create(); wl_display_set_global_filter(m_sWLDisplay, ::filterGlobals, nullptr); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index f2e2ca1497b..295878df2aa 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -24,7 +24,7 @@ enum eManagersInitStage : uint8_t { class CCompositor { public: - CCompositor(); + CCompositor(bool onlyConfig = false); ~CCompositor(); wl_display* m_sWLDisplay; @@ -71,10 +71,11 @@ class CCompositor { bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bNextIsUnsafe = false; PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state - bool m_bIsShuttingDown = false; - bool m_bFinalRequests = false; - bool m_bDesktopEnvSet = false; - bool m_bWantsXwayland = true; + bool m_bIsShuttingDown = false; + bool m_bFinalRequests = false; + bool m_bDesktopEnvSet = false; + bool m_bWantsXwayland = true; + bool m_bOnlyConfigVerification = false; // ------------------------------------------------- // diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f5c9b3eed61..c5d70329389 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -19,6 +19,7 @@ #include "../render/Renderer.hpp" #include "../hyprerror/HyprError.hpp" #include "../managers/input/InputManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/LayoutManager.hpp" #include "../managers/EventManager.hpp" #include "../debug/HyprNotificationOverlay.hpp" @@ -730,15 +731,18 @@ CConfigManager::CConfigManager() { resetHLConfig(); - Debug::log(INFO, - "!!!!HEY YOU, YES YOU!!!!: further logs to stdout / logfile are disabled by default. BEFORE SENDING THIS LOG, ENABLE THEM. Use debug:disable_logs = false to do so: " - "https://wiki.hyprland.org/Configuring/Variables/#debug"); + if (!g_pCompositor->m_bOnlyConfigVerification) { + Debug::log( + INFO, + "!!!!HEY YOU, YES YOU!!!!: further logs to stdout / logfile are disabled by default. BEFORE SENDING THIS LOG, ENABLE THEM. Use debug:disable_logs = false to do so: " + "https://wiki.hyprland.org/Configuring/Variables/#debug"); + } Debug::disableLogs = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:disable_logs")->getDataStaticPtr()); Debug::disableTime = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr()); - if (ERR.has_value()) - g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0}); + if (g_pEventLoopManager && ERR.has_value()) + g_pEventLoopManager->doLater([ERR] { g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0}); }); } std::optional CConfigManager::generateConfig(std::string configPath) { @@ -820,11 +824,23 @@ void CConfigManager::reload() { EMIT_HOOK_EVENT("preConfigReload", nullptr); setDefaultAnimationVars(); resetHLConfig(); - configCurrentPath = getMainConfigPath(); - const auto ERR = m_pConfig->parse(); + configCurrentPath = getMainConfigPath(); + const auto ERR = m_pConfig->parse(); + m_bLastConfigVerificationWasSuccessful = !ERR.error; postConfigReload(ERR); } +std::string CConfigManager::verify() { + setDefaultAnimationVars(); + resetHLConfig(); + configCurrentPath = getMainConfigPath(); + const auto ERR = m_pConfig->parse(); + m_bLastConfigVerificationWasSuccessful = !ERR.error; + if (ERR.error) + return ERR.getError(); + return "config ok"; +} + void CConfigManager::setDefaultAnimationVars() { m_AnimationTree.createNode("__internal_fadeCTM"); m_AnimationTree.createNode("global"); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 31ad81cdcc4..564c1ebfef8 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -144,6 +144,7 @@ class CConfigManager { void init(); void reload(); + std::string verify(); int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = ""); float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = ""); @@ -257,9 +258,10 @@ class CConfigManager { {"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }}, {"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}}; - bool m_bWantsMonitorReload = false; - bool m_bNoMonitorReload = false; - bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking + bool m_bWantsMonitorReload = false; + bool m_bNoMonitorReload = false; + bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking + bool m_bLastConfigVerificationWasSuccessful = true; private: UP m_pConfig; diff --git a/src/main.cpp b/src/main.cpp index bb5e5622efa..d244f10f54a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ static void help() { --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover) --systeminfo - Prints system infos --i-am-really-stupid - Omits root user privileges check (why would you do that?) + --verify-config - Do not run Hyprland, only print if the config has any errors --version -v - Print this binary's version)"); } @@ -49,7 +50,7 @@ int main(int argc, char** argv) { std::string configPath; std::string socketName; int socketFd = -1; - bool ignoreSudo = false; + bool ignoreSudo = false, verifyConfig = false; std::vector args{argv + 1, argv + argc}; @@ -124,6 +125,9 @@ int main(int argc, char** argv) { } else if (*it == "--systeminfo") { std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0; + } else if (*it == "--verify-config") { + verifyConfig = true; + continue; } else { std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it); help(); @@ -138,9 +142,8 @@ int main(int argc, char** argv) { " Hint: Use the --i-am-really-stupid flag to omit that check."); return 1; - } else if (ignoreSudo && NInit::isSudo()) { + } else if (ignoreSudo && NInit::isSudo()) std::println("Superuser privileges check is omitted. I hope you know what you're doing."); - } if (socketName.empty() ^ (socketFd == -1)) { std::println(stderr, @@ -150,12 +153,13 @@ int main(int argc, char** argv) { return 1; } - std::println("Welcome to Hyprland!"); + if (!verifyConfig) + std::println("Welcome to Hyprland!"); // let's init the compositor. // it initializes basic Wayland stuff in the constructor. try { - g_pCompositor = makeUnique(); + g_pCompositor = makeUnique(verifyConfig); g_pCompositor->explicitConfigPath = configPath; } catch (const std::exception& e) { std::println(stderr, "Hyprland threw in ctor: {}\nCannot continue.", e.what()); @@ -164,6 +168,9 @@ int main(int argc, char** argv) { g_pCompositor->initServer(socketName, socketFd); + if (verifyConfig) + return !g_pConfigManager->m_bLastConfigVerificationWasSuccessful; + if (!envEnabled("HYPRLAND_NO_RT")) NInit::gainRealTime(); diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index f884acdd33e..964f7cfa449 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -34,7 +34,8 @@ static int wlTick(SP self, void* data) { CHyprAnimationManager::CHyprAnimationManager() { m_pAnimationTimer = SP(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr)); - g_pEventLoopManager->addTimer(m_pAnimationTimer); + if (g_pEventLoopManager) // null in --verify-config mode + g_pEventLoopManager->addTimer(m_pAnimationTimer); addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)); } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4706c1e1313..e2191bc66da 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -172,8 +172,11 @@ CKeybindManager::CKeybindManager() { }, nullptr); - g_pEventLoopManager->addTimer(m_pLongPressTimer); - g_pEventLoopManager->addTimer(m_pRepeatKeyTimer); + // null in --verify-config mode + if (g_pEventLoopManager) { + g_pEventLoopManager->addTimer(m_pLongPressTimer); + g_pEventLoopManager->addTimer(m_pRepeatKeyTimer); + } static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { // clear cuz realloc'd