mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-09-30 15:18:28 +00:00
core: add --verify-config to verify the config with Hyprland
fixes #9135
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <print>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "debug/HyprCtl.hpp"
|
#include "debug/HyprCtl.hpp"
|
||||||
#include "debug/CrashReporter.hpp"
|
#include "debug/CrashReporter.hpp"
|
||||||
@@ -162,7 +163,10 @@ void CCompositor::restoreNofile() {
|
|||||||
Debug::log(ERR, "Failed restoring NOFILE limits");
|
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";
|
m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr";
|
||||||
|
|
||||||
if (m_szHyprTempDataRoot.starts_with("/hypr")) {
|
if (m_szHyprTempDataRoot.starts_with("/hypr")) {
|
||||||
@@ -226,7 +230,7 @@ CCompositor::CCompositor() : m_iHyprlandPID(getpid()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CCompositor::~CCompositor() {
|
CCompositor::~CCompositor() {
|
||||||
if (!m_bIsShuttingDown)
|
if (!m_bIsShuttingDown && !m_bOnlyConfigVerification)
|
||||||
cleanup();
|
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) {
|
void CCompositor::initServer(std::string socketName, int socketFd) {
|
||||||
|
|
||||||
|
if (m_bOnlyConfigVerification) {
|
||||||
|
g_pHookSystem = makeUnique<CHookSystemManager>();
|
||||||
|
g_pKeybindManager = makeUnique<CKeybindManager>();
|
||||||
|
g_pAnimationManager = makeUnique<CHyprAnimationManager>();
|
||||||
|
g_pConfigManager = makeUnique<CConfigManager>();
|
||||||
|
|
||||||
|
std::println("\n\n======== Config parsing result:\n\n{}", g_pConfigManager->verify());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_sWLDisplay = wl_display_create();
|
m_sWLDisplay = wl_display_create();
|
||||||
|
|
||||||
wl_display_set_global_filter(m_sWLDisplay, ::filterGlobals, nullptr);
|
wl_display_set_global_filter(m_sWLDisplay, ::filterGlobals, nullptr);
|
||||||
|
@@ -24,7 +24,7 @@ enum eManagersInitStage : uint8_t {
|
|||||||
|
|
||||||
class CCompositor {
|
class CCompositor {
|
||||||
public:
|
public:
|
||||||
CCompositor();
|
CCompositor(bool onlyConfig = false);
|
||||||
~CCompositor();
|
~CCompositor();
|
||||||
|
|
||||||
wl_display* m_sWLDisplay;
|
wl_display* m_sWLDisplay;
|
||||||
@@ -75,6 +75,7 @@ class CCompositor {
|
|||||||
bool m_bFinalRequests = false;
|
bool m_bFinalRequests = false;
|
||||||
bool m_bDesktopEnvSet = false;
|
bool m_bDesktopEnvSet = false;
|
||||||
bool m_bWantsXwayland = true;
|
bool m_bWantsXwayland = true;
|
||||||
|
bool m_bOnlyConfigVerification = false;
|
||||||
|
|
||||||
// ------------------------------------------------- //
|
// ------------------------------------------------- //
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include "../render/Renderer.hpp"
|
#include "../render/Renderer.hpp"
|
||||||
#include "../hyprerror/HyprError.hpp"
|
#include "../hyprerror/HyprError.hpp"
|
||||||
#include "../managers/input/InputManager.hpp"
|
#include "../managers/input/InputManager.hpp"
|
||||||
|
#include "../managers/eventLoop/EventLoopManager.hpp"
|
||||||
#include "../managers/LayoutManager.hpp"
|
#include "../managers/LayoutManager.hpp"
|
||||||
#include "../managers/EventManager.hpp"
|
#include "../managers/EventManager.hpp"
|
||||||
#include "../debug/HyprNotificationOverlay.hpp"
|
#include "../debug/HyprNotificationOverlay.hpp"
|
||||||
@@ -730,15 +731,18 @@ CConfigManager::CConfigManager() {
|
|||||||
|
|
||||||
resetHLConfig();
|
resetHLConfig();
|
||||||
|
|
||||||
Debug::log(INFO,
|
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: "
|
"!!!!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");
|
"https://wiki.hyprland.org/Configuring/Variables/#debug");
|
||||||
|
}
|
||||||
|
|
||||||
Debug::disableLogs = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_logs")->getDataStaticPtr());
|
Debug::disableLogs = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_logs")->getDataStaticPtr());
|
||||||
Debug::disableTime = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr());
|
Debug::disableTime = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr());
|
||||||
|
|
||||||
if (ERR.has_value())
|
if (g_pEventLoopManager && ERR.has_value())
|
||||||
g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0});
|
g_pEventLoopManager->doLater([ERR] { g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0}); });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
|
std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
|
||||||
@@ -822,9 +826,21 @@ void CConfigManager::reload() {
|
|||||||
resetHLConfig();
|
resetHLConfig();
|
||||||
configCurrentPath = getMainConfigPath();
|
configCurrentPath = getMainConfigPath();
|
||||||
const auto ERR = m_pConfig->parse();
|
const auto ERR = m_pConfig->parse();
|
||||||
|
m_bLastConfigVerificationWasSuccessful = !ERR.error;
|
||||||
postConfigReload(ERR);
|
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() {
|
void CConfigManager::setDefaultAnimationVars() {
|
||||||
m_AnimationTree.createNode("__internal_fadeCTM");
|
m_AnimationTree.createNode("__internal_fadeCTM");
|
||||||
m_AnimationTree.createNode("global");
|
m_AnimationTree.createNode("global");
|
||||||
|
@@ -144,6 +144,7 @@ class CConfigManager {
|
|||||||
|
|
||||||
void init();
|
void init();
|
||||||
void reload();
|
void reload();
|
||||||
|
std::string verify();
|
||||||
|
|
||||||
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
||||||
@@ -260,6 +261,7 @@ class CConfigManager {
|
|||||||
bool m_bWantsMonitorReload = false;
|
bool m_bWantsMonitorReload = false;
|
||||||
bool m_bNoMonitorReload = false;
|
bool m_bNoMonitorReload = false;
|
||||||
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
|
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
|
||||||
|
bool m_bLastConfigVerificationWasSuccessful = true;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UP<Hyprlang::CConfig> m_pConfig;
|
UP<Hyprlang::CConfig> m_pConfig;
|
||||||
|
15
src/main.cpp
15
src/main.cpp
@@ -27,6 +27,7 @@ static void help() {
|
|||||||
--wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)
|
--wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)
|
||||||
--systeminfo - Prints system infos
|
--systeminfo - Prints system infos
|
||||||
--i-am-really-stupid - Omits root user privileges check (why would you do that?)
|
--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)");
|
--version -v - Print this binary's version)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ int main(int argc, char** argv) {
|
|||||||
std::string configPath;
|
std::string configPath;
|
||||||
std::string socketName;
|
std::string socketName;
|
||||||
int socketFd = -1;
|
int socketFd = -1;
|
||||||
bool ignoreSudo = false;
|
bool ignoreSudo = false, verifyConfig = false;
|
||||||
|
|
||||||
std::vector<std::string> args{argv + 1, argv + argc};
|
std::vector<std::string> args{argv + 1, argv + argc};
|
||||||
|
|
||||||
@@ -124,6 +125,9 @@ int main(int argc, char** argv) {
|
|||||||
} else if (*it == "--systeminfo") {
|
} else if (*it == "--systeminfo") {
|
||||||
std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""));
|
std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""));
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (*it == "--verify-config") {
|
||||||
|
verifyConfig = true;
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it);
|
std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it);
|
||||||
help();
|
help();
|
||||||
@@ -138,9 +142,8 @@ int main(int argc, char** argv) {
|
|||||||
" Hint: Use the --i-am-really-stupid flag to omit that check.");
|
" Hint: Use the --i-am-really-stupid flag to omit that check.");
|
||||||
|
|
||||||
return 1;
|
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.");
|
std::println("Superuser privileges check is omitted. I hope you know what you're doing.");
|
||||||
}
|
|
||||||
|
|
||||||
if (socketName.empty() ^ (socketFd == -1)) {
|
if (socketName.empty() ^ (socketFd == -1)) {
|
||||||
std::println(stderr,
|
std::println(stderr,
|
||||||
@@ -150,12 +153,13 @@ int main(int argc, char** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!verifyConfig)
|
||||||
std::println("Welcome to Hyprland!");
|
std::println("Welcome to Hyprland!");
|
||||||
|
|
||||||
// let's init the compositor.
|
// let's init the compositor.
|
||||||
// it initializes basic Wayland stuff in the constructor.
|
// it initializes basic Wayland stuff in the constructor.
|
||||||
try {
|
try {
|
||||||
g_pCompositor = makeUnique<CCompositor>();
|
g_pCompositor = makeUnique<CCompositor>(verifyConfig);
|
||||||
g_pCompositor->explicitConfigPath = configPath;
|
g_pCompositor->explicitConfigPath = configPath;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::println(stderr, "Hyprland threw in ctor: {}\nCannot continue.", e.what());
|
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);
|
g_pCompositor->initServer(socketName, socketFd);
|
||||||
|
|
||||||
|
if (verifyConfig)
|
||||||
|
return !g_pConfigManager->m_bLastConfigVerificationWasSuccessful;
|
||||||
|
|
||||||
if (!envEnabled("HYPRLAND_NO_RT"))
|
if (!envEnabled("HYPRLAND_NO_RT"))
|
||||||
NInit::gainRealTime();
|
NInit::gainRealTime();
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@ static int wlTick(SP<CEventLoopTimer> self, void* data) {
|
|||||||
|
|
||||||
CHyprAnimationManager::CHyprAnimationManager() {
|
CHyprAnimationManager::CHyprAnimationManager() {
|
||||||
m_pAnimationTimer = SP<CEventLoopTimer>(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr));
|
m_pAnimationTimer = SP<CEventLoopTimer>(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr));
|
||||||
|
if (g_pEventLoopManager) // null in --verify-config mode
|
||||||
g_pEventLoopManager->addTimer(m_pAnimationTimer);
|
g_pEventLoopManager->addTimer(m_pAnimationTimer);
|
||||||
|
|
||||||
addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0));
|
addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0));
|
||||||
|
@@ -172,8 +172,11 @@ CKeybindManager::CKeybindManager() {
|
|||||||
},
|
},
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
|
// null in --verify-config mode
|
||||||
|
if (g_pEventLoopManager) {
|
||||||
g_pEventLoopManager->addTimer(m_pLongPressTimer);
|
g_pEventLoopManager->addTimer(m_pLongPressTimer);
|
||||||
g_pEventLoopManager->addTimer(m_pRepeatKeyTimer);
|
g_pEventLoopManager->addTimer(m_pRepeatKeyTimer);
|
||||||
|
}
|
||||||
|
|
||||||
static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) {
|
static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) {
|
||||||
// clear cuz realloc'd
|
// clear cuz realloc'd
|
||||||
|
Reference in New Issue
Block a user