mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-22 21:49:49 +01:00
core: Add support for hyprqtutils' update screen (#8651)
* Nix: add hyprland-qtutils to PATH * flake.lock: update --------- Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
parent
5ff02902ee
commit
b1e5cc66bd
11 changed files with 270 additions and 13 deletions
45
flake.lock
45
flake.lock
|
@ -141,6 +141,32 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-qtutils": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
"hyprutils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733472316,
|
||||
"narHash": "sha256-PvXiFLIExJEJj+goLbIuXLTN5CSDSAUsAfiYSdbbWg0=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qtutils",
|
||||
"rev": "969427419276c7ee170301ef1ebe0f68eb6eb2e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qtutils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprlang": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
|
@ -215,11 +241,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1732758367,
|
||||
"narHash": "sha256-RzaI1RO0UXqLjydtz3GAXSTzHkpb/lLD1JD8a0W4Wpo=",
|
||||
"lastModified": 1733392399,
|
||||
"narHash": "sha256-kEsTJTUQfQFIJOcLYFt/RvNxIK653ZkTBIs4DG+cBns=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "fa42b5a5f401aab8a32bd33c9a4de0738180dc59",
|
||||
"rev": "d0797a04b81caeae77bcff10a9dde78bc17f5661",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -255,11 +281,11 @@
|
|||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1732021966,
|
||||
"narHash": "sha256-mnTbjpdqF0luOkou8ZFi2asa1N3AA2CchR/RqCNmsGE=",
|
||||
"lastModified": 1733318908,
|
||||
"narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "3308484d1a443fc5bc92012435d79e80458fe43c",
|
||||
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -274,6 +300,7 @@
|
|||
"hyprcursor": "hyprcursor",
|
||||
"hyprgraphics": "hyprgraphics",
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"hyprland-qtutils": "hyprland-qtutils",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||
|
@ -320,11 +347,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731703417,
|
||||
"narHash": "sha256-rheDc/7C+yI+QspYr9J2z9kQ5P9F4ATapI7qyFAe1XA=",
|
||||
"lastModified": 1733157064,
|
||||
"narHash": "sha256-NetqJHAN4bbZDQADvpep+wXk2AbMZ2bN6tINz8Kpz6M=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "8070f36deec723de71e7557441acb17e478204d3",
|
||||
"rev": "fd85ef39369f95eed67fdf3f025e86916edeea2f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -35,6 +35,13 @@
|
|||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprland-qtutils = {
|
||||
url = "github:hyprwm/hyprland-qtutils";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprutils.follows = "hyprutils";
|
||||
};
|
||||
|
||||
hyprlang = {
|
||||
url = "github:hyprwm/hyprlang";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
@ -123,13 +130,11 @@
|
|||
inherit
|
||||
(pkgsFor.${system})
|
||||
# hyprland-packages
|
||||
|
||||
hyprland
|
||||
hyprland-debug
|
||||
hyprland-legacy-renderer
|
||||
hyprland-unwrapped
|
||||
# hyprland-extras
|
||||
|
||||
xdg-desktop-portal-hyprland
|
||||
;
|
||||
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
hyprcursor,
|
||||
hyprgraphics,
|
||||
hyprland-protocols,
|
||||
hyprland-qtutils,
|
||||
hyprlang,
|
||||
hyprutils,
|
||||
hyprwayland-scanner,
|
||||
|
@ -168,6 +169,7 @@ in
|
|||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${makeBinPath [
|
||||
binutils
|
||||
hyprland-qtutils
|
||||
pciutils
|
||||
pkgconf
|
||||
]}
|
||||
|
|
|
@ -24,6 +24,7 @@ in {
|
|||
inputs.hyprcursor.overlays.default
|
||||
inputs.hyprgraphics.overlays.default
|
||||
inputs.hyprland-protocols.overlays.default
|
||||
inputs.hyprland-qtutils.overlays.default
|
||||
inputs.hyprlang.overlays.default
|
||||
inputs.hyprutils.overlays.default
|
||||
inputs.hyprwayland-scanner.overlays.default
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "managers/TokenManager.hpp"
|
||||
#include "managers/PointerManager.hpp"
|
||||
#include "managers/SeatManager.hpp"
|
||||
#include "managers/VersionKeeperManager.hpp"
|
||||
#include "managers/eventLoop/EventLoopManager.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <bit>
|
||||
|
@ -645,6 +646,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
|
|||
Debug::log(LOG, "Creating the CursorManager!");
|
||||
g_pCursorManager = std::make_unique<CCursorManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the VersionKeeper!");
|
||||
g_pVersionKeeperMgr = std::make_unique<CVersionKeeperManager>();
|
||||
|
||||
Debug::log(LOG, "Starting XWayland");
|
||||
g_pXWayland = std::make_unique<CXWayland>(g_pCompositor->m_bEnableXwayland);
|
||||
} break;
|
||||
|
@ -2611,6 +2615,7 @@ WORKSPACEID CCompositor::getNewSpecialID() {
|
|||
|
||||
void CCompositor::performUserChecks() {
|
||||
static auto PNOCHECKXDG = CConfigValue<Hyprlang::INT>("misc:disable_xdg_env_checks");
|
||||
static auto PNOCHECKQTUTILS = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_qtutils_check");
|
||||
|
||||
if (!*PNOCHECKXDG) {
|
||||
const auto CURRENT_DESKTOP_ENV = getenv("XDG_CURRENT_DESKTOP");
|
||||
|
@ -2622,6 +2627,13 @@ void CCompositor::performUserChecks() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!*PNOCHECKQTUTILS) {
|
||||
if (!executableExistsInPath("hyprland-dialog")) {
|
||||
g_pHyprNotificationOverlay->addNotification(
|
||||
"Your system does not have hyprland-qtutils installed. This is a runtime dependency for some dialogs. Consider installing it.", CHyprColor{}, 15000, ICON_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_pHyprOpenGL->failedAssetsNo > 0) {
|
||||
g_pHyprNotificationOverlay->addNotification(std::format("Hyprland failed to load {} essential asset{}, blame your distro's packager for doing a bad job at packaging!",
|
||||
g_pHyprOpenGL->failedAssetsNo, g_pHyprOpenGL->failedAssetsNo > 1 ? "s" : ""),
|
||||
|
|
|
@ -1133,6 +1133,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
|||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:disable_hyprland_qtutils_check",
|
||||
.description = "disable the warning if hyprland-qtutils is missing",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.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.",
|
||||
|
|
|
@ -383,6 +383,7 @@ CConfigManager::CConfigManager() {
|
|||
m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1});
|
||||
m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15});
|
||||
m_pConfig->addConfigValue("misc:disable_xdg_env_checks", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("misc:disable_hyprland_qtutils_check", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("misc:lockdead_screen_delay", Hyprlang::INT{1000});
|
||||
|
||||
m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1});
|
||||
|
@ -606,6 +607,8 @@ CConfigManager::CConfigManager() {
|
|||
m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("render:expand_undersized_textures", Hyprlang::INT{1});
|
||||
|
||||
m_pConfig->addConfigValue("ecosystem:no_update_news", Hyprlang::INT{0});
|
||||
|
||||
// devices
|
||||
m_pConfig->addSpecialCategory("device", {"name"});
|
||||
m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F});
|
||||
|
|
|
@ -930,4 +930,34 @@ float stringToPercentage(const std::string& VALUE, const float REL) {
|
|||
return (std::stof(VALUE.substr(0, VALUE.length() - 1)) * REL) / 100.f;
|
||||
else
|
||||
return std::stof(VALUE);
|
||||
};
|
||||
}
|
||||
|
||||
bool executableExistsInPath(const std::string& exe) {
|
||||
if (!getenv("PATH"))
|
||||
return false;
|
||||
|
||||
static CVarList paths(getenv("PATH"), 0, ':', true);
|
||||
|
||||
for (auto& p : paths) {
|
||||
std::string path = p + std::string{"/"} + exe;
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::exists(path, ec) || ec)
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::is_regular_file(path, ec) || ec)
|
||||
continue;
|
||||
|
||||
auto stat = std::filesystem::status(path, ec);
|
||||
if (ec)
|
||||
continue;
|
||||
|
||||
auto perms = stat.permissions();
|
||||
|
||||
if (std::filesystem::perms::none == (perms & std::filesystem::perms::others_exec))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ bool envEnabled(const std::string& env);
|
|||
int allocateSHMFile(size_t len);
|
||||
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
|
||||
float stringToPercentage(const std::string& VALUE, const float REL);
|
||||
bool executableExistsInPath(const std::string& exe);
|
||||
|
||||
template <typename... Args>
|
||||
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
|
||||
|
|
153
src/managers/VersionKeeperManager.cpp
Normal file
153
src/managers/VersionKeeperManager.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
#include "VersionKeeperManager.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include "../version.h"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
#include "eventLoop/EventLoopManager.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
constexpr const char* VERSION_FILE_NAME = "lastVersion";
|
||||
|
||||
CVersionKeeperManager::CVersionKeeperManager() {
|
||||
static auto PNONOTIFY = CConfigValue<Hyprlang::INT>("ecosystem:no_update_news");
|
||||
|
||||
const auto DATAROOT = getDataHome();
|
||||
|
||||
if (!DATAROOT)
|
||||
return;
|
||||
|
||||
const auto LASTVER = getDataLastVersion(*DATAROOT);
|
||||
|
||||
if (!LASTVER)
|
||||
return;
|
||||
|
||||
if (!isVersionOlderThanRunning(*LASTVER)) {
|
||||
Debug::log(LOG, "CVersionKeeperManager: Read version {} matches or is older than running.", *LASTVER);
|
||||
return;
|
||||
}
|
||||
|
||||
writeVersionToVersionFile(*DATAROOT);
|
||||
|
||||
if (*PNONOTIFY) {
|
||||
Debug::log(LOG, "CVersionKeeperManager: updated, but update news is disabled in the config :(");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!executableExistsInPath("hyprland-update-screen")) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: hyprland-update-screen doesn't seem to exist, skipping notif about update...");
|
||||
return;
|
||||
}
|
||||
|
||||
g_pEventLoopManager->doLater([]() {
|
||||
CProcess proc("hyprland-update-screen", {"--new-version", HYPRLAND_VERSION});
|
||||
proc.runAsync();
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<std::string> CVersionKeeperManager::getDataHome() {
|
||||
const auto DATA_HOME = getenv("XDG_DATA_HOME");
|
||||
|
||||
std::string dataRoot;
|
||||
|
||||
if (!DATA_HOME) {
|
||||
const auto HOME = getenv("HOME");
|
||||
|
||||
if (!HOME) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: can't get data home: no $HOME or $XDG_DATA_HOME");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
dataRoot = HOME + std::string{"/.local/share/"};
|
||||
} else
|
||||
dataRoot = DATA_HOME + std::string{"/"};
|
||||
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::exists(dataRoot, ec) || ec) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: can't get data home: inaccessible / missing");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
dataRoot += "hyprland/";
|
||||
|
||||
if (!std::filesystem::exists(dataRoot, ec) || ec) {
|
||||
Debug::log(LOG, "CVersionKeeperManager: no hyprland data home, creating.");
|
||||
std::filesystem::create_directory(dataRoot, ec);
|
||||
if (ec) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: can't create new data home for hyprland");
|
||||
return std::nullopt;
|
||||
}
|
||||
std::filesystem::permissions(dataRoot, std::filesystem::perms::owner_read | std::filesystem::perms::owner_write | std::filesystem::perms::owner_exec, ec);
|
||||
if (ec)
|
||||
Debug::log(WARN, "CVersionKeeperManager: couldn't set perms on hyprland data store. Proceeding anyways.");
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(dataRoot, ec) || ec) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: no hyprland data home, failed to create.");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return dataRoot;
|
||||
}
|
||||
|
||||
std::optional<std::string> CVersionKeeperManager::getDataLastVersion(const std::string& dataRoot) {
|
||||
std::error_code ec;
|
||||
std::string lastVerFile = dataRoot + "/" + VERSION_FILE_NAME;
|
||||
|
||||
if (!std::filesystem::exists(lastVerFile, ec) || ec) {
|
||||
Debug::log(LOG, "CVersionKeeperManager: no hyprland last version file, creating.");
|
||||
writeVersionToVersionFile(dataRoot);
|
||||
|
||||
return HYPRLAND_VERSION;
|
||||
}
|
||||
|
||||
std::ifstream file(lastVerFile);
|
||||
if (!file.good()) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: couldn't open an ifstream for reading the version file.");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return trim(std::string((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())));
|
||||
}
|
||||
|
||||
void CVersionKeeperManager::writeVersionToVersionFile(const std::string& dataRoot) {
|
||||
std::string lastVerFile = dataRoot + "/" + VERSION_FILE_NAME;
|
||||
std::ofstream of(lastVerFile, std::ios::trunc);
|
||||
if (!of.good()) {
|
||||
Debug::log(ERR, "CVersionKeeperManager: couldn't open an ofstream for writing the version file.");
|
||||
return;
|
||||
}
|
||||
|
||||
of << HYPRLAND_VERSION;
|
||||
of.close();
|
||||
}
|
||||
|
||||
bool CVersionKeeperManager::isVersionOlderThanRunning(const std::string& ver) {
|
||||
const CVarList verStrings(ver, 0, '.', true);
|
||||
|
||||
const int V1 = configStringToInt(verStrings[0]).value_or(0);
|
||||
const int V2 = configStringToInt(verStrings[1]).value_or(0);
|
||||
const int V3 = configStringToInt(verStrings[2]).value_or(0);
|
||||
|
||||
static const CVarList runningStrings(HYPRLAND_VERSION, 0, '.', true);
|
||||
|
||||
static const int R1 = configStringToInt(runningStrings[0]).value_or(0);
|
||||
static const int R2 = configStringToInt(runningStrings[1]).value_or(0);
|
||||
static const int R3 = configStringToInt(runningStrings[2]).value_or(0);
|
||||
|
||||
if (R1 > V1)
|
||||
return true;
|
||||
if (R2 > V2)
|
||||
return true;
|
||||
if (R3 > V3)
|
||||
return true;
|
||||
return false;
|
||||
}
|
17
src/managers/VersionKeeperManager.hpp
Normal file
17
src/managers/VersionKeeperManager.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
class CVersionKeeperManager {
|
||||
public:
|
||||
CVersionKeeperManager();
|
||||
|
||||
private:
|
||||
std::optional<std::string> getDataHome();
|
||||
std::optional<std::string> getDataLastVersion(const std::string& dataRoot);
|
||||
void writeVersionToVersionFile(const std::string& dataRoot);
|
||||
bool isVersionOlderThanRunning(const std::string& ver);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CVersionKeeperManager> g_pVersionKeeperMgr;
|
Loading…
Reference in a new issue