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
|
|
@ -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;
|
||||
|
|
@ -2610,7 +2614,8 @@ WORKSPACEID CCompositor::getNewSpecialID() {
|
|||
}
|
||||
|
||||
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 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…
Add table
Add a link
Reference in a new issue