mirror of
https://github.com/hyprwm/Hyprland.git
synced 2026-02-04 03:25:29 +00:00
start: use nixGL if Hyprland is nix but not NixOS (#12845)
--------- Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
#include "Instance.hpp"
|
||||
#include "State.hpp"
|
||||
#include "../helpers/Logger.hpp"
|
||||
#include "../helpers/Nix.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -54,7 +55,12 @@ void CHyprlandInstance::runHyprlandThread(bool safeMode) {
|
||||
procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &sig);
|
||||
#endif
|
||||
|
||||
execvp(g_state->customPath.value_or("Hyprland").c_str(), args.data());
|
||||
if (Nix::shouldUseNixGL()) {
|
||||
argsStd.insert(argsStd.begin(), g_state->customPath.value_or("Hyprland"));
|
||||
args.insert(args.begin(), strdup(argsStd.front().c_str()));
|
||||
execvp("nixGL", args.data());
|
||||
} else
|
||||
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);
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
struct SState {
|
||||
std::span<const char*> rawArgvNoBinPath;
|
||||
std::optional<std::string> customPath;
|
||||
bool noNixGl = false;
|
||||
};
|
||||
|
||||
inline UP<SState> g_state = makeUnique<SState>();
|
||||
110
start/src/helpers/Nix.cpp
Normal file
110
start/src/helpers/Nix.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include "Nix.hpp"
|
||||
|
||||
#include "Logger.hpp"
|
||||
#include "../core/State.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <hyprutils/string/VarList2.hpp>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
#include <hyprutils/os/File.hpp>
|
||||
|
||||
#include <glaze/glaze.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
using namespace Hyprutils::File;
|
||||
|
||||
static std::optional<std::string> getFromEtcOsRelease(const std::string_view& sv) {
|
||||
static std::string content = "";
|
||||
static bool once = true;
|
||||
|
||||
if (once) {
|
||||
once = false;
|
||||
|
||||
auto read = readFileAsString("/etc/os-release");
|
||||
content = read.value_or("");
|
||||
}
|
||||
|
||||
static CVarList2 vars(std::move(content), 0, '\n', true);
|
||||
|
||||
for (const auto& v : vars) {
|
||||
if (v.starts_with(sv) && v.contains('=')) {
|
||||
// found
|
||||
auto value = trim(v.substr(v.find('=') + 1));
|
||||
|
||||
if (value.back() == value.front() && value.back() == '"')
|
||||
value = value.substr(1, value.size() - 2);
|
||||
|
||||
return std::string{value};
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static bool executableExistsInPath(const std::string& exe) {
|
||||
const char* PATHENV = std::getenv("PATH");
|
||||
if (!PATHENV)
|
||||
return false;
|
||||
|
||||
CVarList2 paths(PATHENV, 0, ':', true);
|
||||
std::error_code ec;
|
||||
|
||||
for (const auto& PATH : paths) {
|
||||
std::filesystem::path candidate = std::filesystem::path(PATH) / exe;
|
||||
if (!std::filesystem::exists(candidate, ec) || ec)
|
||||
continue;
|
||||
if (!std::filesystem::is_regular_file(candidate, ec) || ec)
|
||||
continue;
|
||||
auto perms = std::filesystem::status(candidate, ec).permissions();
|
||||
if (ec)
|
||||
continue;
|
||||
if ((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::expected<void, std::string> Nix::nixEnvironmentOk() {
|
||||
if (!shouldUseNixGL())
|
||||
return {};
|
||||
|
||||
if (!executableExistsInPath("nixGL"))
|
||||
return std::unexpected(
|
||||
"Hyprland was installed using Nix, but you're not on NixOS. This requires nixGL to be installed as well.\nYou can install nixGL by running \"nix profile install "
|
||||
"github:guibou/nixGL --impure\" in your terminal.");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Nix::shouldUseNixGL() {
|
||||
if (g_state->noNixGl)
|
||||
return false;
|
||||
|
||||
// check if installed hyprland is nix'd
|
||||
CProcess proc("Hyprland", {"--version-json"});
|
||||
if (!proc.runSync()) {
|
||||
g_logger->log(Hyprutils::CLI::LOG_ERR, "failed to obtain hyprland version string");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto json = glz::read_json<glz::generic>(proc.stdOut());
|
||||
if (!json) {
|
||||
g_logger->log(Hyprutils::CLI::LOG_ERR, "failed to obtain hyprland version string (bad json)");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto FLAGS = (*json)["flags"].get_array();
|
||||
const bool IS_NIX = std::ranges::any_of(FLAGS, [](const auto& e) { return e.get_string() == std::string_view{"nix"}; });
|
||||
|
||||
if (IS_NIX) {
|
||||
const auto NAME = getFromEtcOsRelease("NAME");
|
||||
return !NAME || *NAME != "NixOS";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
9
start/src/helpers/Nix.hpp
Normal file
9
start/src/helpers/Nix.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
|
||||
namespace Nix {
|
||||
std::expected<void, std::string> nixEnvironmentOk();
|
||||
bool shouldUseNixGL();
|
||||
};
|
||||
@ -3,6 +3,7 @@
|
||||
#include <print>
|
||||
|
||||
#include "helpers/Logger.hpp"
|
||||
#include "helpers/Nix.hpp"
|
||||
#include "core/State.hpp"
|
||||
#include "core/Instance.hpp"
|
||||
|
||||
@ -16,7 +17,12 @@ using namespace Hyprutils::CLI;
|
||||
}
|
||||
|
||||
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)#";
|
||||
Any arguments after -- are passed to Hyprland. For Hyprland help, run start-hyprland -- --help or Hyprland --help
|
||||
|
||||
Additional arguments for start-hyprland:
|
||||
--path [path] -> Override Hyprland path
|
||||
--no-nixgl -> Force disable nixGL
|
||||
)#";
|
||||
|
||||
//
|
||||
static void onSignal(int sig) {
|
||||
@ -69,6 +75,10 @@ int main(int argc, const char** argv, const char** envp) {
|
||||
g_state->customPath = argv[++i];
|
||||
continue;
|
||||
}
|
||||
if (arg == "--no-nixgl") {
|
||||
g_state->noNixGl = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (startArgv != -1)
|
||||
@ -77,6 +87,15 @@ int main(int argc, const char** argv, const char** envp) {
|
||||
if (!g_state->rawArgvNoBinPath.empty())
|
||||
g_logger->log(Hyprutils::CLI::LOG_WARN, "Arguments after -- are passed to Hyprland");
|
||||
|
||||
// check if our environment is OK
|
||||
if (const auto RET = Nix::nixEnvironmentOk(); !RET) {
|
||||
g_logger->log(Hyprutils::CLI::LOG_ERR, "Nix environment check failed:\n{}", RET.error());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Nix::shouldUseNixGL())
|
||||
g_logger->log(Hyprutils::CLI::LOG_DEBUG, "Hyprland was compiled with Nix - will use nixGL");
|
||||
|
||||
bool safeMode = false;
|
||||
while (true) {
|
||||
g_instance = makeUnique<CHyprlandInstance>();
|
||||
|
||||
Reference in New Issue
Block a user