start: init start-hyprland and safe mode (#12484)
This commit is contained in:
parent
ec6756f961
commit
016eb7a23d
22 changed files with 550 additions and 28 deletions
|
|
@ -119,13 +119,13 @@ set(GLES_VERSION "GLES3")
|
||||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||||
|
|
||||||
set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
|
set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
|
||||||
set(HYPERLANG_MINIMUM_VERSION 0.3.2)
|
set(HYPRLANG_MINIMUM_VERSION 0.6.7)
|
||||||
set(HYPRCURSOR_MINIMUM_VERSION 0.1.7)
|
set(HYPRCURSOR_MINIMUM_VERSION 0.1.7)
|
||||||
set(HYPRUTILS_MINIMUM_VERSION 0.10.2)
|
set(HYPRUTILS_MINIMUM_VERSION 0.10.2)
|
||||||
set(HYPRGRAPHICS_MINIMUM_VERSION 0.1.6)
|
set(HYPRGRAPHICS_MINIMUM_VERSION 0.1.6)
|
||||||
|
|
||||||
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=${AQUAMARINE_MINIMUM_VERSION})
|
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=${AQUAMARINE_MINIMUM_VERSION})
|
||||||
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=${HYPERLANG_MINIMUM_VERSION})
|
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=${HYPRLANG_MINIMUM_VERSION})
|
||||||
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=${HYPRCURSOR_MINIMUM_VERSION})
|
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=${HYPRCURSOR_MINIMUM_VERSION})
|
||||||
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=${HYPRUTILS_MINIMUM_VERSION})
|
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=${HYPRUTILS_MINIMUM_VERSION})
|
||||||
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=${HYPRGRAPHICS_MINIMUM_VERSION})
|
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=${HYPRGRAPHICS_MINIMUM_VERSION})
|
||||||
|
|
@ -545,6 +545,7 @@ protocolwayland()
|
||||||
|
|
||||||
# tools
|
# tools
|
||||||
add_subdirectory(hyprctl)
|
add_subdirectory(hyprctl)
|
||||||
|
add_subdirectory(start)
|
||||||
|
|
||||||
if(NO_HYPRPM)
|
if(NO_HYPRPM)
|
||||||
message(STATUS "hyprpm is disabled")
|
message(STATUS "hyprpm is disabled")
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ monitor=,preferred,auto,auto
|
||||||
# Set programs that you use
|
# Set programs that you use
|
||||||
$terminal = kitty
|
$terminal = kitty
|
||||||
$fileManager = dolphin
|
$fileManager = dolphin
|
||||||
$menu = wofi --show drun
|
$menu = hyprlauncher
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
|
|
@ -329,3 +329,13 @@ windowrule {
|
||||||
|
|
||||||
no_focus = true
|
no_focus = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Hyprland-run windowrule
|
||||||
|
windowrule {
|
||||||
|
name = move-hyprland-run
|
||||||
|
|
||||||
|
match:class = hyprland-run
|
||||||
|
|
||||||
|
move = 20 monitor_h-120
|
||||||
|
float = yes
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=Hyprland
|
Name=Hyprland
|
||||||
Comment=An intelligent dynamic tiling Wayland compositor
|
Comment=An intelligent dynamic tiling Wayland compositor
|
||||||
Exec=Hyprland
|
Exec=start-hyprland
|
||||||
Type=Application
|
Type=Application
|
||||||
DesktopNames=Hyprland
|
DesktopNames=Hyprland
|
||||||
Keywords=tiling;wayland;compositor;
|
Keywords=tiling;wayland;compositor;
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ Name: Hyprland
|
||||||
URL: https://github.com/hyprwm/Hyprland
|
URL: https://github.com/hyprwm/Hyprland
|
||||||
Description: Hyprland header files
|
Description: Hyprland header files
|
||||||
Version: @HYPRLAND_VERSION@
|
Version: @HYPRLAND_VERSION@
|
||||||
Requires: aquamarine >= @AQUAMARINE_MINIMUM_VERSION@, hyprcursor >= @HYPRCURSOR_MINIMUM_VERSION@, hyprgraphics >= @HYPRGRAPHICS_MINIMUM_VERSION@, hyprlang >= @HYPERLANG_MINIMUM_VERSION@, hyprutils >= @HYPRUTILS_MINIMUM_VERSION@, libdrm, egl, cairo, xkbcommon >= @XKBCOMMMON_MINIMUM_VERSION@, libinput >= @LIBINPUT_MINIMUM_VERSION@, wayland-server >= @WAYLAND_SERVER_MINIMUM_VERSION@@PKGCONFIG_XWAYLAND_DEPENDENCIES@
|
Requires: aquamarine >= @AQUAMARINE_MINIMUM_VERSION@, hyprcursor >= @HYPRCURSOR_MINIMUM_VERSION@, hyprgraphics >= @HYPRGRAPHICS_MINIMUM_VERSION@, hyprlang >= @HYPRLANG_MINIMUM_VERSION@, hyprutils >= @HYPRUTILS_MINIMUM_VERSION@, libdrm, egl, cairo, xkbcommon >= @XKBCOMMMON_MINIMUM_VERSION@, libinput >= @LIBINPUT_MINIMUM_VERSION@, wayland-server >= @WAYLAND_SERVER_MINIMUM_VERSION@@PKGCONFIG_XWAYLAND_DEPENDENCIES@
|
||||||
Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland
|
Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland
|
||||||
|
|
|
||||||
|
|
@ -585,6 +585,7 @@ bool CPluginManager::updateHeaders(bool force) {
|
||||||
std::filesystem::remove_all(WORKINGDIR);
|
std::filesystem::remove_all(WORKINGDIR);
|
||||||
|
|
||||||
auto HEADERSVALID = headersValid();
|
auto HEADERSVALID = headersValid();
|
||||||
|
|
||||||
if (HEADERSVALID == HEADERS_OK || HEADERSVALID == HEADERS_MISMATCHED || HEADERSVALID == HEADERS_ABI_MISMATCH) {
|
if (HEADERSVALID == HEADERS_OK || HEADERSVALID == HEADERS_MISMATCHED || HEADERSVALID == HEADERS_ABI_MISMATCH) {
|
||||||
progress.printMessageAbove(successString("installed headers"));
|
progress.printMessageAbove(successString("installed headers"));
|
||||||
progress.m_iSteps = 5;
|
progress.m_iSteps = 5;
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ in
|
||||||
../LICENSE
|
../LICENSE
|
||||||
../protocols
|
../protocols
|
||||||
../src
|
../src
|
||||||
|
../start
|
||||||
../systemd
|
../systemd
|
||||||
../VERSION
|
../VERSION
|
||||||
(fs.fileFilter (file: file.hasExt "1") ../docs)
|
(fs.fileFilter (file: file.hasExt "1") ../docs)
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,10 @@ static void aqLog(Aquamarine::eBackendLogLevel level, std::string msg) {
|
||||||
Debug::log(aqLevelToHl(level), "[AQ] {}", msg);
|
Debug::log(aqLevelToHl(level), "[AQ] {}", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCompositor::setWatchdogFd(int fd) {
|
||||||
|
m_watchdogWriteFd = Hyprutils::OS::CFileDescriptor{fd};
|
||||||
|
}
|
||||||
|
|
||||||
void CCompositor::bumpNofile() {
|
void CCompositor::bumpNofile() {
|
||||||
if (!getrlimit(RLIMIT_NOFILE, &m_originalNofile))
|
if (!getrlimit(RLIMIT_NOFILE, &m_originalNofile))
|
||||||
Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_originalNofile.rlim_cur, m_originalNofile.rlim_max);
|
Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_originalNofile.rlim_cur, m_originalNofile.rlim_max);
|
||||||
|
|
@ -543,6 +547,9 @@ void CCompositor::cleanup() {
|
||||||
if (!m_wlDisplay)
|
if (!m_wlDisplay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (m_watchdogWriteFd.isValid())
|
||||||
|
write(m_watchdogWriteFd.get(), "end", 3);
|
||||||
|
|
||||||
signal(SIGABRT, SIG_DFL);
|
signal(SIGABRT, SIG_DFL);
|
||||||
signal(SIGSEGV, SIG_DFL);
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
|
||||||
|
|
@ -796,6 +803,8 @@ void CCompositor::startCompositor() {
|
||||||
createLockFile();
|
createLockFile();
|
||||||
|
|
||||||
EMIT_HOOK_EVENT("ready", nullptr);
|
EMIT_HOOK_EVENT("ready", nullptr);
|
||||||
|
if (m_watchdogWriteFd.isValid())
|
||||||
|
write(m_watchdogWriteFd.get(), "vax", 3);
|
||||||
|
|
||||||
// This blocks until we are done.
|
// This blocks until we are done.
|
||||||
Debug::log(LOG, "Hyprland is ready, running the event loop!");
|
Debug::log(LOG, "Hyprland is ready, running the event loop!");
|
||||||
|
|
@ -2459,6 +2468,7 @@ std::vector<PHLWORKSPACE> CCompositor::getWorkspacesCopy() {
|
||||||
void CCompositor::performUserChecks() {
|
void CCompositor::performUserChecks() {
|
||||||
static auto PNOCHECKXDG = CConfigValue<Hyprlang::INT>("misc:disable_xdg_env_checks");
|
static auto PNOCHECKXDG = CConfigValue<Hyprlang::INT>("misc:disable_xdg_env_checks");
|
||||||
static auto PNOCHECKGUIUTILS = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_guiutils_check");
|
static auto PNOCHECKGUIUTILS = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_guiutils_check");
|
||||||
|
static auto PNOWATCHDOG = CConfigValue<Hyprlang::INT>("misc:disable_watchdog_warning");
|
||||||
|
|
||||||
if (!*PNOCHECKXDG) {
|
if (!*PNOCHECKXDG) {
|
||||||
const auto CURRENT_DESKTOP_ENV = getenv("XDG_CURRENT_DESKTOP");
|
const auto CURRENT_DESKTOP_ENV = getenv("XDG_CURRENT_DESKTOP");
|
||||||
|
|
@ -2470,15 +2480,63 @@ void CCompositor::performUserChecks() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*PNOCHECKGUIUTILS) {
|
if (!*PNOCHECKGUIUTILS) {
|
||||||
if (!NFsUtils::executableExistsInPath("hyprland-dialog")) {
|
if (!NFsUtils::executableExistsInPath("hyprland-dialog"))
|
||||||
g_pHyprNotificationOverlay->addNotification(I18n::i18nEngine()->localize(I18n::TXT_KEY_NOTIF_NO_GUIUTILS), CHyprColor{}, 15000, ICON_WARNING);
|
g_pHyprNotificationOverlay->addNotification(I18n::i18nEngine()->localize(I18n::TXT_KEY_NOTIF_NO_GUIUTILS), CHyprColor{}, 15000, ICON_WARNING);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_pHyprOpenGL->m_failedAssetsNo > 0) {
|
if (g_pHyprOpenGL->m_failedAssetsNo > 0) {
|
||||||
g_pHyprNotificationOverlay->addNotification(I18n::i18nEngine()->localize(I18n::TXT_KEY_NOTIF_FAILED_ASSETS, {{"count", std::to_string(g_pHyprOpenGL->m_failedAssetsNo)}}),
|
g_pHyprNotificationOverlay->addNotification(I18n::i18nEngine()->localize(I18n::TXT_KEY_NOTIF_FAILED_ASSETS, {{"count", std::to_string(g_pHyprOpenGL->m_failedAssetsNo)}}),
|
||||||
CHyprColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
|
CHyprColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_watchdogWriteFd.isValid() && !*PNOWATCHDOG)
|
||||||
|
g_pHyprNotificationOverlay->addNotification(I18n::i18nEngine()->localize(I18n::TXT_KEY_NOTIF_NO_WATCHDOG), CHyprColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_WARNING);
|
||||||
|
|
||||||
|
if (m_safeMode)
|
||||||
|
openSafeModeBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCompositor::openSafeModeBox() {
|
||||||
|
const auto OPT_LOAD = I18n::i18nEngine()->localize(I18n::TXT_KEY_SAFE_MODE_BUTTON_LOAD_CONFIG);
|
||||||
|
const auto OPT_OPEN = I18n::i18nEngine()->localize(I18n::TXT_KEY_SAFE_MODE_BUTTON_OPEN_CRASH_REPORT_DIR);
|
||||||
|
const auto OPT_OK = I18n::i18nEngine()->localize(I18n::TXT_KEY_SAFE_MODE_BUTTON_UNDERSTOOD);
|
||||||
|
|
||||||
|
auto box = CAsyncDialogBox::create(I18n::i18nEngine()->localize(I18n::TXT_KEY_SAFE_MODE_TITLE), I18n::i18nEngine()->localize(I18n::TXT_KEY_SAFE_MODE_DESCRIPTION),
|
||||||
|
{
|
||||||
|
OPT_LOAD,
|
||||||
|
OPT_OPEN,
|
||||||
|
OPT_OK,
|
||||||
|
});
|
||||||
|
|
||||||
|
box->open()->then([OPT_LOAD, OPT_OK, OPT_OPEN, this](SP<CPromiseResult<std::string>> result) {
|
||||||
|
if (result->hasError())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto RES = result->result();
|
||||||
|
|
||||||
|
if (RES.starts_with(OPT_LOAD)) {
|
||||||
|
m_safeMode = false;
|
||||||
|
g_pConfigManager->reload();
|
||||||
|
} else if (RES.starts_with(OPT_OPEN)) {
|
||||||
|
std::string reportPath;
|
||||||
|
const auto HOME = getenv("HOME");
|
||||||
|
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
||||||
|
|
||||||
|
if (CACHE_HOME && CACHE_HOME[0] != '\0') {
|
||||||
|
reportPath += CACHE_HOME;
|
||||||
|
reportPath += "/hyprland/";
|
||||||
|
} else if (HOME && HOME[0] != '\0') {
|
||||||
|
reportPath += HOME;
|
||||||
|
reportPath += "/.cache/hyprland/";
|
||||||
|
}
|
||||||
|
Hyprutils::OS::CProcess proc("xdg-open", {reportPath});
|
||||||
|
|
||||||
|
proc.runAsync();
|
||||||
|
|
||||||
|
// reopen
|
||||||
|
openSafeModeBox();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) {
|
void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ class CCompositor {
|
||||||
} m_drmRenderNode;
|
} m_drmRenderNode;
|
||||||
|
|
||||||
bool m_initialized = false;
|
bool m_initialized = false;
|
||||||
|
bool m_safeMode = false;
|
||||||
SP<Aquamarine::CBackend> m_aqBackend;
|
SP<Aquamarine::CBackend> m_aqBackend;
|
||||||
|
|
||||||
std::string m_hyprTempDataRoot = "";
|
std::string m_hyprTempDataRoot = "";
|
||||||
|
|
@ -65,6 +66,7 @@ class CCompositor {
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void bumpNofile();
|
void bumpNofile();
|
||||||
void restoreNofile();
|
void restoreNofile();
|
||||||
|
void setWatchdogFd(int fd);
|
||||||
|
|
||||||
bool m_readyToProcess = false;
|
bool m_readyToProcess = false;
|
||||||
bool m_sessionActive = true;
|
bool m_sessionActive = true;
|
||||||
|
|
@ -167,21 +169,23 @@ class CCompositor {
|
||||||
std::string m_explicitConfigPath;
|
std::string m_explicitConfigPath;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initAllSignals();
|
void initAllSignals();
|
||||||
void removeAllSignals();
|
void removeAllSignals();
|
||||||
void cleanEnvironment();
|
void cleanEnvironment();
|
||||||
void setRandomSplash();
|
void setRandomSplash();
|
||||||
void initManagers(eManagersInitStage stage);
|
void initManagers(eManagersInitStage stage);
|
||||||
void prepareFallbackOutput();
|
void prepareFallbackOutput();
|
||||||
void createLockFile();
|
void createLockFile();
|
||||||
void removeLockFile();
|
void removeLockFile();
|
||||||
void setMallocThreshold();
|
void setMallocThreshold();
|
||||||
|
void openSafeModeBox();
|
||||||
|
|
||||||
uint64_t m_hyprlandPID = 0;
|
uint64_t m_hyprlandPID = 0;
|
||||||
wl_event_source* m_critSigSource = nullptr;
|
wl_event_source* m_critSigSource = nullptr;
|
||||||
rlimit m_originalNofile = {};
|
rlimit m_originalNofile = {};
|
||||||
|
Hyprutils::OS::CFileDescriptor m_watchdogWriteFd;
|
||||||
|
|
||||||
std::vector<PHLWORKSPACEREF> m_workspaces;
|
std::vector<PHLWORKSPACEREF> m_workspaces;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline UP<CCompositor> g_pCompositor;
|
inline UP<CCompositor> g_pCompositor;
|
||||||
|
|
|
||||||
|
|
@ -1321,6 +1321,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||||
.type = CONFIG_OPTION_BOOL,
|
.type = CONFIG_OPTION_BOOL,
|
||||||
.data = SConfigOptionDescription::SBoolData{false},
|
.data = SConfigOptionDescription::SBoolData{false},
|
||||||
},
|
},
|
||||||
|
SConfigOptionDescription{
|
||||||
|
.value = "misc:disable_watchdog_warning",
|
||||||
|
.description = "whether to disable the warning about not using start-hyprland.",
|
||||||
|
.type = CONFIG_OPTION_BOOL,
|
||||||
|
.data = SConfigOptionDescription::SBoolData{false},
|
||||||
|
},
|
||||||
SConfigOptionDescription{
|
SConfigOptionDescription{
|
||||||
.value = "misc:lockdead_screen_delay",
|
.value = "misc:lockdead_screen_delay",
|
||||||
.description = "the delay in ms after the lockdead screen appears if the lock screen did not appear after a lock event occurred.",
|
.description = "the delay in ms after the lockdead screen appears if the lock screen did not appear after a lock event occurred.",
|
||||||
|
|
|
||||||
|
|
@ -498,6 +498,7 @@ CConfigManager::CConfigManager() {
|
||||||
registerConfigVar("misc:render_unfocused_fps", Hyprlang::INT{15});
|
registerConfigVar("misc:render_unfocused_fps", Hyprlang::INT{15});
|
||||||
registerConfigVar("misc:disable_xdg_env_checks", Hyprlang::INT{0});
|
registerConfigVar("misc:disable_xdg_env_checks", Hyprlang::INT{0});
|
||||||
registerConfigVar("misc:disable_hyprland_guiutils_check", Hyprlang::INT{0});
|
registerConfigVar("misc:disable_hyprland_guiutils_check", Hyprlang::INT{0});
|
||||||
|
registerConfigVar("misc:disable_watchdog_warning", Hyprlang::INT{0});
|
||||||
registerConfigVar("misc:lockdead_screen_delay", Hyprlang::INT{1000});
|
registerConfigVar("misc:lockdead_screen_delay", Hyprlang::INT{1000});
|
||||||
registerConfigVar("misc:enable_anr_dialog", Hyprlang::INT{1});
|
registerConfigVar("misc:enable_anr_dialog", Hyprlang::INT{1});
|
||||||
registerConfigVar("misc:anr_missed_pings", Hyprlang::INT{5});
|
registerConfigVar("misc:anr_missed_pings", Hyprlang::INT{5});
|
||||||
|
|
@ -914,7 +915,7 @@ void CConfigManager::reloadRuleConfigs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
|
std::optional<std::string> CConfigManager::generateConfig(std::string configPath, bool safeMode) {
|
||||||
std::string parentPath = std::filesystem::path(configPath).parent_path();
|
std::string parentPath = std::filesystem::path(configPath).parent_path();
|
||||||
|
|
||||||
if (!parentPath.empty()) {
|
if (!parentPath.empty()) {
|
||||||
|
|
@ -931,7 +932,14 @@ std::optional<std::string> CConfigManager::generateConfig(std::string configPath
|
||||||
Debug::log(WARN, "No config file found; attempting to generate.");
|
Debug::log(WARN, "No config file found; attempting to generate.");
|
||||||
std::ofstream ofs;
|
std::ofstream ofs;
|
||||||
ofs.open(configPath, std::ios::trunc);
|
ofs.open(configPath, std::ios::trunc);
|
||||||
ofs << AUTOGENERATED_PREFIX << EXAMPLE_CONFIG;
|
if (!safeMode) {
|
||||||
|
ofs << AUTOGENERATED_PREFIX;
|
||||||
|
ofs << EXAMPLE_CONFIG;
|
||||||
|
} else {
|
||||||
|
std::string n = std::string{EXAMPLE_CONFIG};
|
||||||
|
replaceInString(n, "\n$menu = hyprlauncher\n", "\n$menu = hyprland-run\n");
|
||||||
|
ofs << n;
|
||||||
|
}
|
||||||
ofs.close();
|
ofs.close();
|
||||||
|
|
||||||
if (ofs.fail())
|
if (ofs.fail())
|
||||||
|
|
@ -941,7 +949,16 @@ std::optional<std::string> CConfigManager::generateConfig(std::string configPath
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CConfigManager::getMainConfigPath() {
|
std::string CConfigManager::getMainConfigPath() {
|
||||||
static std::string CONFIG_PATH = [this]() -> std::string {
|
static bool lastSafeMode = g_pCompositor->m_safeMode;
|
||||||
|
static auto getCfgPath = [this]() -> std::string {
|
||||||
|
lastSafeMode = g_pCompositor->m_safeMode;
|
||||||
|
m_firstExecDispatched = false;
|
||||||
|
|
||||||
|
if (g_pCompositor->m_safeMode) {
|
||||||
|
const auto CONFIGPATH = g_pCompositor->m_instancePath + "/recoverycfg.conf";
|
||||||
|
return generateConfig(CONFIGPATH, false).value();
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_pCompositor->m_explicitConfigPath.empty())
|
if (!g_pCompositor->m_explicitConfigPath.empty())
|
||||||
return g_pCompositor->m_explicitConfigPath;
|
return g_pCompositor->m_explicitConfigPath;
|
||||||
|
|
||||||
|
|
@ -956,7 +973,13 @@ std::string CConfigManager::getMainConfigPath() {
|
||||||
return generateConfig(CONFIGPATH).value();
|
return generateConfig(CONFIGPATH).value();
|
||||||
} else
|
} else
|
||||||
throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg.");
|
throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg.");
|
||||||
}();
|
};
|
||||||
|
static std::string CONFIG_PATH = getCfgPath();
|
||||||
|
|
||||||
|
if (lastSafeMode != g_pCompositor->m_safeMode) {
|
||||||
|
CONFIG_PATH = getCfgPath();
|
||||||
|
m_config->changeRootPath(CONFIG_PATH.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
return CONFIG_PATH;
|
return CONFIG_PATH;
|
||||||
}
|
}
|
||||||
|
|
@ -1415,7 +1438,6 @@ void CConfigManager::init() {
|
||||||
reload();
|
reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
const std::string CONFIGPATH = getMainConfigPath();
|
|
||||||
reload();
|
reload();
|
||||||
|
|
||||||
m_isFirstLaunch = false;
|
m_isFirstLaunch = false;
|
||||||
|
|
@ -1637,7 +1659,12 @@ void CConfigManager::dispatchExecOnce() {
|
||||||
g_pInputManager->setTabletConfigs();
|
g_pInputManager->setTabletConfigs();
|
||||||
|
|
||||||
// check for user's possible errors with their setup and notify them if needed
|
// check for user's possible errors with their setup and notify them if needed
|
||||||
g_pCompositor->performUserChecks();
|
// this is additionally guarded because exiting safe mode will re-run this.
|
||||||
|
static bool once = true;
|
||||||
|
if (once) {
|
||||||
|
g_pCompositor->performUserChecks();
|
||||||
|
once = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConfigManager::dispatchExecShutdown() {
|
void CConfigManager::dispatchExecShutdown() {
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,7 @@ class CConfigManager {
|
||||||
// internal methods
|
// internal methods
|
||||||
void setDefaultAnimationVars();
|
void setDefaultAnimationVars();
|
||||||
std::optional<std::string> resetHLConfig();
|
std::optional<std::string> resetHLConfig();
|
||||||
std::optional<std::string> generateConfig(std::string configPath);
|
std::optional<std::string> generateConfig(std::string configPath, bool safeMode = false);
|
||||||
std::optional<std::string> verifyConfigExists();
|
std::optional<std::string> verifyConfigExists();
|
||||||
void reloadRuleConfigs();
|
void reloadRuleConfigs();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,18 @@ I18n::CI18nEngine::CI18nEngine() {
|
||||||
huEngine->registerEntry("en_US", TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN, "Failed to load plugin {name}: {error}");
|
huEngine->registerEntry("en_US", TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN, "Failed to load plugin {name}: {error}");
|
||||||
huEngine->registerEntry("en_US", TXT_KEY_NOTIF_CM_RELOAD_FAILED, "CM shader reload failed, falling back to rgba/rgbx.");
|
huEngine->registerEntry("en_US", TXT_KEY_NOTIF_CM_RELOAD_FAILED, "CM shader reload failed, falling back to rgba/rgbx.");
|
||||||
huEngine->registerEntry("en_US", TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B, "Monitor {name}: wide color gamut is enabled but the display is not in 10-bit mode.");
|
huEngine->registerEntry("en_US", TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B, "Monitor {name}: wide color gamut is enabled but the display is not in 10-bit mode.");
|
||||||
|
huEngine->registerEntry("en_US", TXT_KEY_NOTIF_NO_WATCHDOG,
|
||||||
|
"Hyprland was started without start-hyprland. This is highly not recommended unless you are in a debugging environment.");
|
||||||
|
|
||||||
|
huEngine->registerEntry("en_US", TXT_KEY_SAFE_MODE_TITLE, "Safe Mode");
|
||||||
|
huEngine->registerEntry("en_US", TXT_KEY_SAFE_MODE_DESCRIPTION,
|
||||||
|
"Hyprland has been launched in safe mode, which means your last session crashed.\nSafe mode prevents your config from being loaded. You can "
|
||||||
|
"troubleshoot in this environment, or load your config with the button below.\nDefault keybinds apply: SUPER+Q for kitty, SUPER+R for a basic runner, "
|
||||||
|
"SUPER+M to exit.\nRestarting "
|
||||||
|
"Hyprland will launch in normal mode again.");
|
||||||
|
huEngine->registerEntry("en_US", TXT_KEY_SAFE_MODE_BUTTON_LOAD_CONFIG, "Load config");
|
||||||
|
huEngine->registerEntry("en_US", TXT_KEY_SAFE_MODE_BUTTON_OPEN_CRASH_REPORT_DIR, "Open crash report directory");
|
||||||
|
huEngine->registerEntry("en_US", TXT_KEY_SAFE_MODE_BUTTON_UNDERSTOOD, "Ok, close this");
|
||||||
|
|
||||||
// as_IN (Assamese)
|
// as_IN (Assamese)
|
||||||
huEngine->registerEntry("as_IN", TXT_KEY_ANR_TITLE, "এপ্লিকেচনে উত্তৰ দিয়া নাই");
|
huEngine->registerEntry("as_IN", TXT_KEY_ANR_TITLE, "এপ্লিকেচনে উত্তৰ দিয়া নাই");
|
||||||
|
|
@ -619,6 +631,17 @@ I18n::CI18nEngine::CI18nEngine() {
|
||||||
huEngine->registerEntry("ja_JP", TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN, "プラグイン{name}のロード失敗: {error}");
|
huEngine->registerEntry("ja_JP", TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN, "プラグイン{name}のロード失敗: {error}");
|
||||||
huEngine->registerEntry("ja_JP", TXT_KEY_NOTIF_CM_RELOAD_FAILED, "CMシェーダーのリロード失敗、rgba/rgbxを使いました。");
|
huEngine->registerEntry("ja_JP", TXT_KEY_NOTIF_CM_RELOAD_FAILED, "CMシェーダーのリロード失敗、rgba/rgbxを使いました。");
|
||||||
huEngine->registerEntry("ja_JP", TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B, "画面{name}:広い色域は設定していますけど、画面は10ビットモードに設定されていません。");
|
huEngine->registerEntry("ja_JP", TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B, "画面{name}:広い色域は設定していますけど、画面は10ビットモードに設定されていません。");
|
||||||
|
huEngine->registerEntry("ja_JP", TXT_KEY_NOTIF_NO_WATCHDOG, "Hyprlandはstart-hyprlandなしで実行されました。これはデバグ環境以外でおすすめしません。");
|
||||||
|
|
||||||
|
huEngine->registerEntry("ja_JP", TXT_KEY_SAFE_MODE_TITLE, "安全モード");
|
||||||
|
huEngine->registerEntry(
|
||||||
|
"ja_JP", TXT_KEY_SAFE_MODE_DESCRIPTION,
|
||||||
|
"Hyprlandは安全モードに実行しました。これは、Hyprlandはクラッシュしましたから。\n安全モードはコンフィグをロードしなくて、問題を修正できる環境です。下のボタンでコンフィグを"
|
||||||
|
"ロードできます。\nデフォルトなキーバインドがあります。SUPER+Qはkitty、SUPER+Rは簡素なランチャー、SUPER+"
|
||||||
|
"MはHyprlandから退出。\nHyprlandを再び実行すれば、普通モードで実行します。");
|
||||||
|
huEngine->registerEntry("ja_JP", TXT_KEY_SAFE_MODE_BUTTON_LOAD_CONFIG, "コンフィグをロード");
|
||||||
|
huEngine->registerEntry("ja_JP", TXT_KEY_SAFE_MODE_BUTTON_OPEN_CRASH_REPORT_DIR, "クラッシュレポートフォルダーを開く");
|
||||||
|
huEngine->registerEntry("ja_JP", TXT_KEY_SAFE_MODE_BUTTON_UNDERSTOOD, "分かりました、このウィンドウをクローズ");
|
||||||
|
|
||||||
// lv_LV (Latvian)
|
// lv_LV (Latvian)
|
||||||
huEngine->registerEntry("lv_LV", TXT_KEY_ANR_TITLE, "Lietotne nereaģē");
|
huEngine->registerEntry("lv_LV", TXT_KEY_ANR_TITLE, "Lietotne nereaģē");
|
||||||
|
|
@ -903,6 +926,18 @@ I18n::CI18nEngine::CI18nEngine() {
|
||||||
huEngine->registerEntry("pl_PL", TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN, "Nie udało się załadować plugin'a {name}: {error}");
|
huEngine->registerEntry("pl_PL", TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN, "Nie udało się załadować plugin'a {name}: {error}");
|
||||||
huEngine->registerEntry("pl_PL", TXT_KEY_NOTIF_CM_RELOAD_FAILED, "Nie udało się przeładować shader'a CM, użyto rgba/rgbx.");
|
huEngine->registerEntry("pl_PL", TXT_KEY_NOTIF_CM_RELOAD_FAILED, "Nie udało się przeładować shader'a CM, użyto rgba/rgbx.");
|
||||||
huEngine->registerEntry("pl_PL", TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B, "Monitor {name}: skonfigurowano szeroką głębię barw, ale monitor nie jest w trybie 10-bit.");
|
huEngine->registerEntry("pl_PL", TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B, "Monitor {name}: skonfigurowano szeroką głębię barw, ale monitor nie jest w trybie 10-bit.");
|
||||||
|
huEngine->registerEntry("pl_PL", TXT_KEY_NOTIF_NO_WATCHDOG,
|
||||||
|
"Hyprland został uruchomiony bez start-hyprland. Nie jest to zalecane, chyba, że jest to środowisko do debugowania.");
|
||||||
|
|
||||||
|
huEngine->registerEntry("pl_PL", TXT_KEY_SAFE_MODE_TITLE, "Tryb Bezpieczny");
|
||||||
|
huEngine->registerEntry("pl_PL", TXT_KEY_SAFE_MODE_DESCRIPTION,
|
||||||
|
"Hyprland został uruchomiony w trybie bezpiecznym, co oznacza, że twoja ostatnia sesja uległa awarii.\nTryb bezpieczny zapobiega ładowaniu twojej "
|
||||||
|
"konfiguracji. Możesz próbować rozwiązać"
|
||||||
|
"problem w tym środowisku, lub załadować swoją konfigurację przyciskiem poniżej.\nDomyślne skróty klawiszowe są dostępne: SUPER+Q uruchamia kitty, "
|
||||||
|
"SUPER+R otwiera podstawowy launcher, SUPER+M zamyka Hyprland.\nUruchomienie ponowne Hyprland'a uruchomi go w trybie normalnym.");
|
||||||
|
huEngine->registerEntry("pl_PL", TXT_KEY_SAFE_MODE_BUTTON_LOAD_CONFIG, "Załaduj konfigurację");
|
||||||
|
huEngine->registerEntry("pl_PL", TXT_KEY_SAFE_MODE_BUTTON_OPEN_CRASH_REPORT_DIR, "Otwórz folder z raportami awarii");
|
||||||
|
huEngine->registerEntry("pl_PL", TXT_KEY_SAFE_MODE_BUTTON_UNDERSTOOD, "Ok, zamknij to okno");
|
||||||
|
|
||||||
// pt_PT (Portuguese Portugal)
|
// pt_PT (Portuguese Portugal)
|
||||||
huEngine->registerEntry("pt_PT", TXT_KEY_ANR_TITLE, "A aplicação não está a responder");
|
huEngine->registerEntry("pt_PT", TXT_KEY_ANR_TITLE, "A aplicação não está a responder");
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,13 @@ namespace I18n {
|
||||||
TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN,
|
TXT_KEY_NOTIF_FAILED_TO_LOAD_PLUGIN,
|
||||||
TXT_KEY_NOTIF_CM_RELOAD_FAILED,
|
TXT_KEY_NOTIF_CM_RELOAD_FAILED,
|
||||||
TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B,
|
TXT_KEY_NOTIF_WIDE_COLOR_NOT_10B,
|
||||||
|
TXT_KEY_NOTIF_NO_WATCHDOG,
|
||||||
|
|
||||||
|
TXT_KEY_SAFE_MODE_TITLE,
|
||||||
|
TXT_KEY_SAFE_MODE_DESCRIPTION,
|
||||||
|
TXT_KEY_SAFE_MODE_BUTTON_OPEN_CRASH_REPORT_DIR,
|
||||||
|
TXT_KEY_SAFE_MODE_BUTTON_LOAD_CONFIG,
|
||||||
|
TXT_KEY_SAFE_MODE_BUTTON_UNDERSTOOD,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CI18nEngine {
|
class CI18nEngine {
|
||||||
|
|
|
||||||
24
src/main.cpp
24
src/main.cpp
|
|
@ -68,7 +68,8 @@ 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, verifyConfig = false;
|
bool ignoreSudo = false, verifyConfig = false, safeMode = false;
|
||||||
|
int watchdogFd = -1;
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
std::span<char*> args{argv + 1, sc<std::size_t>(argc - 1)};
|
std::span<char*> args{argv + 1, sc<std::size_t>(argc - 1)};
|
||||||
|
|
@ -152,6 +153,23 @@ int main(int argc, char** argv) {
|
||||||
} else if (value == "--verify-config") {
|
} else if (value == "--verify-config") {
|
||||||
verifyConfig = true;
|
verifyConfig = true;
|
||||||
continue;
|
continue;
|
||||||
|
} else if (value == "--safe-mode") {
|
||||||
|
safeMode = true;
|
||||||
|
continue;
|
||||||
|
} else if (value == "--watchdog-fd") {
|
||||||
|
if (std::next(it) == args.end()) {
|
||||||
|
help();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
watchdogFd = std::stoi(*std::next(it));
|
||||||
|
it++;
|
||||||
|
} catch (...) {
|
||||||
|
std::println(stderr, "[ ERROR ] Invalid fd for watchdog fd");
|
||||||
|
help();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::println(stderr, "[ ERROR ] Unknown option '{}' !", value);
|
std::println(stderr, "[ ERROR ] Unknown option '{}' !", value);
|
||||||
help();
|
help();
|
||||||
|
|
@ -193,6 +211,10 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
reapZombieChildrenAutomatically();
|
reapZombieChildrenAutomatically();
|
||||||
|
|
||||||
|
if (watchdogFd > 0)
|
||||||
|
g_pCompositor->setWatchdogFd(watchdogFd);
|
||||||
|
if (safeMode)
|
||||||
|
g_pCompositor->m_safeMode = true;
|
||||||
g_pCompositor->initServer(socketName, socketFd);
|
g_pCompositor->initServer(socketName, socketFd);
|
||||||
|
|
||||||
if (verifyConfig)
|
if (verifyConfig)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "../helpers/defer/Promise.hpp"
|
#include "../helpers/defer/Promise.hpp"
|
||||||
|
#include "../helpers/time/Timer.hpp"
|
||||||
#include "PluginAPI.hpp"
|
#include "PluginAPI.hpp"
|
||||||
#include "../managers/permissions/DynamicPermissionManager.hpp"
|
#include "../managers/permissions/DynamicPermissionManager.hpp"
|
||||||
#include <csetjmp>
|
#include <csetjmp>
|
||||||
|
|
|
||||||
24
start/CMakeLists.txt
Normal file
24
start/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(start-hyprland DESCRIPTION "Hyprland watchdog binary")
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 26)
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
||||||
|
pkg_check_modules(starthyprland_deps REQUIRED IMPORTED_TARGET hyprutils>=0.10.3)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||||
|
|
||||||
|
add_executable(start-hyprland ${SRCFILES})
|
||||||
|
|
||||||
|
target_link_libraries(start-hyprland PUBLIC PkgConfig::starthyprland_deps)
|
||||||
|
|
||||||
|
install(TARGETS start-hyprland)
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||||
|
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
|
||||||
|
endif()
|
||||||
165
start/src/core/Instance.cpp
Normal file
165
start/src/core/Instance.cpp
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
#include "Instance.hpp"
|
||||||
|
#include "State.hpp"
|
||||||
|
#include "../helpers/Logger.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ranges>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <hyprutils/os/Process.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
//
|
||||||
|
void CHyprlandInstance::runHyprlandThread(bool safeMode) {
|
||||||
|
std::vector<std::string> argsStd;
|
||||||
|
argsStd.emplace_back("--watchdog-fd");
|
||||||
|
argsStd.emplace_back(std::format("{}", m_toHlPid.get()));
|
||||||
|
if (safeMode)
|
||||||
|
argsStd.emplace_back("--safe-mode");
|
||||||
|
|
||||||
|
for (const auto& a : g_state->rawArgvNoBinPath) {
|
||||||
|
argsStd.emplace_back(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawn a process manually. Hyprutils' Async is detached, while Sync redirects stdout
|
||||||
|
// TODO: make Sync respect fds?
|
||||||
|
|
||||||
|
std::vector<char*> args = {strdup(g_state->customPath.value_or("Hyprland").c_str())};
|
||||||
|
for (const auto& a : argsStd) {
|
||||||
|
args.emplace_back(strdup(a.c_str()));
|
||||||
|
}
|
||||||
|
args.emplace_back(nullptr);
|
||||||
|
|
||||||
|
int forkRet = fork();
|
||||||
|
if (forkRet == 0) {
|
||||||
|
// Make hyprland die on our SIGKILL
|
||||||
|
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||||
|
|
||||||
|
execvp(g_state->customPath.value_or("Hyprland").c_str(), args.data());
|
||||||
|
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_ERR, "fork(): execvp failed: {}", strerror(errno));
|
||||||
|
std::fflush(stdout);
|
||||||
|
exit(1);
|
||||||
|
} else
|
||||||
|
m_hlPid = forkRet;
|
||||||
|
|
||||||
|
m_hlThread = std::thread([this] {
|
||||||
|
while (true) {
|
||||||
|
int status = 0;
|
||||||
|
int ret = waitpid(m_hlPid, &status, 0);
|
||||||
|
if (ret == -1) {
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_ERR, "Couldn't waitpid for hyprland: {}", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write(m_wakeupWrite.get(), "vax", 3);
|
||||||
|
|
||||||
|
std::fflush(stdout);
|
||||||
|
std::fflush(stderr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprlandInstance::forceQuit() {
|
||||||
|
m_hyprlandExiting = true;
|
||||||
|
kill(m_hlPid, SIGTERM); // gracefully, can get stuck but it's unlikely
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprlandInstance::clearFd(const Hyprutils::OS::CFileDescriptor& fd) {
|
||||||
|
static std::array<char, 1024> buf;
|
||||||
|
read(fd.get(), buf.data(), 1023);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprlandInstance::dispatchHyprlandEvent() {
|
||||||
|
std::string recvd = "";
|
||||||
|
static std::array<char, 4096> buf;
|
||||||
|
ssize_t n = read(m_fromHlPid.get(), buf.data(), 4096);
|
||||||
|
if (n < 0) {
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_ERR, "Failed dispatching hl events");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recvd.append(buf.data(), n);
|
||||||
|
|
||||||
|
if (recvd.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto& s : std::views::split(recvd, '\n')) {
|
||||||
|
const std::string_view sv = std::string_view{s};
|
||||||
|
if (sv == "vax") {
|
||||||
|
// init passed
|
||||||
|
m_hyprlandInitialized = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sv == "end") {
|
||||||
|
// exiting
|
||||||
|
m_hyprlandExiting = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHyprlandInstance::run(bool safeMode) {
|
||||||
|
int pipefds[2];
|
||||||
|
pipe(pipefds);
|
||||||
|
|
||||||
|
m_fromHlPid = CFileDescriptor{pipefds[0]};
|
||||||
|
m_toHlPid = CFileDescriptor{pipefds[1]};
|
||||||
|
|
||||||
|
pipe(pipefds);
|
||||||
|
|
||||||
|
m_wakeupRead = CFileDescriptor{pipefds[0]};
|
||||||
|
m_wakeupWrite = CFileDescriptor{pipefds[1]};
|
||||||
|
|
||||||
|
runHyprlandThread(safeMode);
|
||||||
|
|
||||||
|
pollfd pollfds[2] = {
|
||||||
|
{
|
||||||
|
.fd = m_wakeupRead.get(),
|
||||||
|
.events = POLLIN,
|
||||||
|
.revents = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.fd = m_fromHlPid.get(),
|
||||||
|
.events = POLLIN,
|
||||||
|
.revents = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int ret = poll(pollfds, 2, -1);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_ERR, "poll() failed, exiting");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollfds[1].revents & POLLIN) {
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_DEBUG, "got an event from hyprland");
|
||||||
|
dispatchHyprlandEvent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollfds[0].revents & POLLIN) {
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_DEBUG, "hyprland exit, breaking poll, checking state");
|
||||||
|
clearFd(m_wakeupRead);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hlThread.join();
|
||||||
|
|
||||||
|
return !m_hyprlandInitialized || m_hyprlandExiting;
|
||||||
|
}
|
||||||
36
start/src/core/Instance.hpp
Normal file
36
start/src/core/Instance.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprutils/os/FileDescriptor.hpp>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "../helpers/Memory.hpp"
|
||||||
|
|
||||||
|
class CHyprlandInstance {
|
||||||
|
public:
|
||||||
|
CHyprlandInstance() = default;
|
||||||
|
~CHyprlandInstance() = default;
|
||||||
|
|
||||||
|
CHyprlandInstance(const CHyprlandInstance&) = delete;
|
||||||
|
CHyprlandInstance(CHyprlandInstance&) = delete;
|
||||||
|
CHyprlandInstance(CHyprlandInstance&&) = delete;
|
||||||
|
|
||||||
|
bool run(bool safeMode = false); // if returns false, restart.
|
||||||
|
void forceQuit();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void runHyprlandThread(bool safeMode);
|
||||||
|
void clearFd(const Hyprutils::OS::CFileDescriptor& fd);
|
||||||
|
void dispatchHyprlandEvent();
|
||||||
|
|
||||||
|
int m_hlPid = -1;
|
||||||
|
|
||||||
|
Hyprutils::OS::CFileDescriptor m_fromHlPid, m_toHlPid;
|
||||||
|
Hyprutils::OS::CFileDescriptor m_wakeupRead, m_wakeupWrite;
|
||||||
|
|
||||||
|
bool m_hyprlandInitialized = false;
|
||||||
|
bool m_hyprlandExiting = false;
|
||||||
|
|
||||||
|
std::thread m_hlThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline UP<CHyprlandInstance> g_instance;
|
||||||
13
start/src/core/State.hpp
Normal file
13
start/src/core/State.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../helpers/Memory.hpp"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
struct SState {
|
||||||
|
std::span<const char*> rawArgvNoBinPath;
|
||||||
|
std::optional<std::string> customPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline UP<SState> g_state = makeUnique<SState>();
|
||||||
9
start/src/helpers/Logger.hpp
Normal file
9
start/src/helpers/Logger.hpp
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprutils/cli/Logger.hpp>
|
||||||
|
|
||||||
|
#include "Memory.hpp"
|
||||||
|
|
||||||
|
// we do this to add a from start-hyprland to the logs
|
||||||
|
inline UP<Hyprutils::CLI::CLogger> g_loggerMain = makeUnique<Hyprutils::CLI::CLogger>();
|
||||||
|
inline UP<Hyprutils::CLI::CLoggerConnection> g_logger;
|
||||||
15
start/src/helpers/Memory.hpp
Normal file
15
start/src/helpers/Memory.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprutils/memory/WeakPtr.hpp>
|
||||||
|
#include <hyprutils/memory/Atomic.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using SP = Hyprutils::Memory::CSharedPointer<T>;
|
||||||
|
template <typename T>
|
||||||
|
using WP = Hyprutils::Memory::CWeakPointer<T>;
|
||||||
|
template <typename T>
|
||||||
|
using UP = Hyprutils::Memory::CUniquePointer<T>;
|
||||||
|
template <typename T>
|
||||||
|
using ASP = Hyprutils::Memory::CAtomicSharedPointer<T>;
|
||||||
87
start/src/main.cpp
Normal file
87
start/src/main.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include <csignal>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
#include "helpers/Logger.hpp"
|
||||||
|
#include "core/State.hpp"
|
||||||
|
#include "core/Instance.hpp"
|
||||||
|
|
||||||
|
using namespace Hyprutils::CLI;
|
||||||
|
|
||||||
|
#define ASSERT(expr) \
|
||||||
|
if (!(expr)) { \
|
||||||
|
g_logger->log(LOG_CRIT, "Failed assertion at line {} in {}: {} was false", __LINE__, \
|
||||||
|
([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find("/src/") + 1); })(), #expr); \
|
||||||
|
std::abort(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char* HELP_INFO = R"#(start-hyprland - A binary to properly start Hyprland via a watchdog process.
|
||||||
|
Any arguments after -- are passed to Hyprland. For Hyprland help, run start-hyprland -- --help or Hyprland --help)#";
|
||||||
|
|
||||||
|
//
|
||||||
|
static void onSignal(int sig) {
|
||||||
|
if (!g_instance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_instance->forceQuit();
|
||||||
|
g_instance.reset();
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char** argv, const char** envp) {
|
||||||
|
g_logger = makeUnique<Hyprutils::CLI::CLoggerConnection>(*g_loggerMain);
|
||||||
|
g_logger->setName("start-hyprland");
|
||||||
|
g_logger->setLogLevel(Hyprutils::CLI::LOG_DEBUG);
|
||||||
|
|
||||||
|
signal(SIGTERM, ::onSignal);
|
||||||
|
signal(SIGINT, ::onSignal);
|
||||||
|
signal(SIGKILL, ::onSignal);
|
||||||
|
|
||||||
|
int startArgv = -1;
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
std::string_view arg = argv[i];
|
||||||
|
|
||||||
|
if (arg == "--") {
|
||||||
|
startArgv = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (arg == "-h" || arg == "--help") {
|
||||||
|
std::println("{}", HELP_INFO);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (arg == "--path" || arg == "-p") {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
std::println("{} requires a path", arg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_state->customPath = argv[++i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startArgv != -1)
|
||||||
|
g_state->rawArgvNoBinPath = std::span<const char*>{argv + startArgv, argc - startArgv};
|
||||||
|
|
||||||
|
if (!g_state->rawArgvNoBinPath.empty())
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_WARN, "Arguments after -- are passed to Hyprland");
|
||||||
|
|
||||||
|
bool safeMode = false;
|
||||||
|
while (true) {
|
||||||
|
g_instance = makeUnique<CHyprlandInstance>();
|
||||||
|
const bool RET = g_instance->run(safeMode);
|
||||||
|
g_instance.reset();
|
||||||
|
|
||||||
|
if (!RET) {
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_ERR, "Hyprland exit not-cleanly, restarting");
|
||||||
|
safeMode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_logger->log(Hyprutils::CLI::LOG_DEBUG, "Hyprland exit cleanly.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue