mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-07 05:18:21 +02:00
Merge branch 'main' of https://github.com/hyprwm/Hyprland into move-center-override
This commit is contained in:
commit
c051ceb6d2
40 changed files with 429 additions and 159 deletions
7
.github/workflows/new-pr-comment.yml
vendored
7
.github/workflows/new-pr-comment.yml
vendored
|
|
@ -7,6 +7,13 @@ on:
|
|||
|
||||
jobs:
|
||||
comment:
|
||||
if: >
|
||||
github.event.pull_request.user.login != 'vaxerski' &&
|
||||
github.event.pull_request.user.login != 'fufexan' &&
|
||||
github.event.pull_request.user.login != 'gulafaran' &&
|
||||
github.event.pull_request.user.login != 'ujint34' &&
|
||||
github.event.pull_request.user.login != 'paideiadilemma' &&
|
||||
github.event.pull_request.user.login != 'notashelf'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
|||
set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
|
||||
set(HYPRLANG_MINIMUM_VERSION 0.6.7)
|
||||
set(HYPRCURSOR_MINIMUM_VERSION 0.1.7)
|
||||
set(HYPRUTILS_MINIMUM_VERSION 0.10.2)
|
||||
set(HYPRUTILS_MINIMUM_VERSION 0.11.0)
|
||||
set(HYPRGRAPHICS_MINIMUM_VERSION 0.1.6)
|
||||
|
||||
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=${AQUAMARINE_MINIMUM_VERSION})
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
|||
auto DATA = toml::table{
|
||||
{"repository", toml::table{
|
||||
{"name", repo.name},
|
||||
{"author", repo.author},
|
||||
{"hash", repo.hash},
|
||||
{"url", repo.url},
|
||||
{"rev", repo.rev}
|
||||
|
|
@ -122,31 +123,32 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
|||
Debug::die("{}", failureString("Failed to write plugin state"));
|
||||
}
|
||||
|
||||
bool DataState::pluginRepoExists(const std::string& urlOrName) {
|
||||
bool DataState::pluginRepoExists(const SPluginRepoIdentifier identifier) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
for (const auto& stateFile : getPluginStates()) {
|
||||
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto AUTHOR = STATE["repository"]["author"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
|
||||
if (URL == urlOrName || NAME == urlOrName)
|
||||
if (identifier.matches(URL, NAME, AUTHOR))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DataState::removePluginRepo(const std::string& urlOrName) {
|
||||
void DataState::removePluginRepo(const SPluginRepoIdentifier identifier) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
for (const auto& stateFile : getPluginStates()) {
|
||||
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
|
||||
if (URL == urlOrName || NAME == urlOrName) {
|
||||
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto AUTHOR = STATE["repository"]["author"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
|
||||
if (identifier.matches(URL, NAME, AUTHOR)) {
|
||||
// unload the plugins!!
|
||||
for (const auto& file : std::filesystem::directory_iterator(stateFile.parent_path())) {
|
||||
if (!file.path().string().ends_with(".so"))
|
||||
|
|
@ -219,16 +221,18 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
|
|||
for (const auto& stateFile : getPluginStates()) {
|
||||
const auto STATE = toml::parse_file(stateFile.c_str());
|
||||
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
const auto REV = STATE["repository"]["rev"].value_or("");
|
||||
const auto HASH = STATE["repository"]["hash"].value_or("");
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto AUTHOR = STATE["repository"]["author"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
const auto REV = STATE["repository"]["rev"].value_or("");
|
||||
const auto HASH = STATE["repository"]["hash"].value_or("");
|
||||
|
||||
SPluginRepository repo;
|
||||
repo.hash = HASH;
|
||||
repo.name = NAME;
|
||||
repo.url = URL;
|
||||
repo.rev = REV;
|
||||
repo.hash = HASH;
|
||||
repo.name = NAME;
|
||||
repo.author = AUTHOR;
|
||||
repo.url = URL;
|
||||
repo.rev = REV;
|
||||
|
||||
for (const auto& [key, val] : STATE) {
|
||||
if (key == "repository")
|
||||
|
|
@ -247,7 +251,7 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
|
|||
return repos;
|
||||
}
|
||||
|
||||
bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
bool DataState::setPluginEnabled(const SPluginRepoIdentifier identifier, bool enabled) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
for (const auto& stateFile : getPluginStates()) {
|
||||
|
|
@ -256,8 +260,17 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
|||
if (key == "repository")
|
||||
continue;
|
||||
|
||||
if (key.str() != name)
|
||||
continue;
|
||||
switch (identifier.type) {
|
||||
case IDENTIFIER_NAME:
|
||||
if (key.str() != identifier.name)
|
||||
continue;
|
||||
break;
|
||||
case IDENTIFIER_AUTHOR_NAME:
|
||||
if (STATE["repository"]["author"] != identifier.author || key.str() != identifier.name)
|
||||
continue;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
const auto FAILED = STATE[key]["failed"].value_or(false);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ namespace DataState {
|
|||
std::vector<std::filesystem::path> getPluginStates();
|
||||
void ensureStateStoreExists();
|
||||
void addNewPluginRepo(const SPluginRepository& repo);
|
||||
void removePluginRepo(const std::string& urlOrName);
|
||||
bool pluginRepoExists(const std::string& urlOrName);
|
||||
void removePluginRepo(const SPluginRepoIdentifier identifier);
|
||||
bool pluginRepoExists(const SPluginRepoIdentifier identifier);
|
||||
void updateGlobalState(const SGlobalState& state);
|
||||
void purgeAllCache();
|
||||
SGlobalState getGlobalState();
|
||||
bool setPluginEnabled(const std::string& name, bool enabled);
|
||||
bool setPluginEnabled(const SPluginRepoIdentifier identifier, bool enabled);
|
||||
std::vector<SPluginRepository> getAllRepositories();
|
||||
};
|
||||
};
|
||||
|
|
|
|||
48
hyprpm/src/core/Plugin.cpp
Normal file
48
hyprpm/src/core/Plugin.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include "Plugin.hpp"
|
||||
|
||||
SPluginRepoIdentifier SPluginRepoIdentifier::fromUrl(const std::string& url) {
|
||||
return SPluginRepoIdentifier{.type = IDENTIFIER_URL, .url = url};
|
||||
}
|
||||
|
||||
SPluginRepoIdentifier SPluginRepoIdentifier::fromName(const std::string& name) {
|
||||
return SPluginRepoIdentifier{.type = IDENTIFIER_NAME, .name = name};
|
||||
}
|
||||
|
||||
SPluginRepoIdentifier SPluginRepoIdentifier::fromAuthorName(const std::string& author, const std::string& name) {
|
||||
return SPluginRepoIdentifier{.type = IDENTIFIER_AUTHOR_NAME, .name = name, .author = author};
|
||||
}
|
||||
|
||||
SPluginRepoIdentifier SPluginRepoIdentifier::fromString(const std::string& string) {
|
||||
if (string.find(':') != std::string::npos) {
|
||||
return SPluginRepoIdentifier{.type = IDENTIFIER_URL, .url = string};
|
||||
} else {
|
||||
auto slashPos = string.find('/');
|
||||
if (slashPos != std::string::npos) {
|
||||
std::string author = string.substr(0, slashPos);
|
||||
std::string name = string.substr(slashPos + 1, string.size() - slashPos - 1);
|
||||
return SPluginRepoIdentifier{.type = IDENTIFIER_AUTHOR_NAME, .name = name, .author = author};
|
||||
} else {
|
||||
return SPluginRepoIdentifier{.type = IDENTIFIER_NAME, .name = string};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string SPluginRepoIdentifier::toString() const {
|
||||
switch (type) {
|
||||
case IDENTIFIER_NAME: return name;
|
||||
case IDENTIFIER_AUTHOR_NAME: return author + '/' + name;
|
||||
case IDENTIFIER_URL: return url;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool SPluginRepoIdentifier::matches(const std::string& url, const std::string& name, const std::string& author) const {
|
||||
switch (type) {
|
||||
case IDENTIFIER_URL: return this->url == url;
|
||||
case IDENTIFIER_NAME: return this->name == name;
|
||||
case IDENTIFIER_AUTHOR_NAME: return this->author == author && this->name == name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -14,6 +14,27 @@ struct SPluginRepository {
|
|||
std::string url;
|
||||
std::string rev;
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::vector<SPlugin> plugins;
|
||||
std::string hash;
|
||||
};
|
||||
};
|
||||
|
||||
enum ePluginRepoIdentifierType {
|
||||
IDENTIFIER_URL,
|
||||
IDENTIFIER_NAME,
|
||||
IDENTIFIER_AUTHOR_NAME
|
||||
};
|
||||
|
||||
struct SPluginRepoIdentifier {
|
||||
ePluginRepoIdentifierType type;
|
||||
std::string url = "";
|
||||
std::string name = "";
|
||||
std::string author = "";
|
||||
|
||||
static SPluginRepoIdentifier fromString(const std::string& string);
|
||||
static SPluginRepoIdentifier fromUrl(const std::string& Url);
|
||||
static SPluginRepoIdentifier fromName(const std::string& name);
|
||||
static SPluginRepoIdentifier fromAuthorName(const std::string& author, const std::string& name);
|
||||
std::string toString() const;
|
||||
bool matches(const std::string& url, const std::string& name, const std::string& author) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <print>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
|
@ -136,7 +137,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
|||
return false;
|
||||
}
|
||||
|
||||
if (DataState::pluginRepoExists(url)) {
|
||||
if (DataState::pluginRepoExists(SPluginRepoIdentifier::fromUrl(url))) {
|
||||
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed."));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -333,10 +334,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
|||
std::string repohash = execAndGet("cd " + m_szWorkingPluginDirectory + " && git rev-parse HEAD");
|
||||
if (repohash.length() > 0)
|
||||
repohash.pop_back();
|
||||
repo.name = pManifest->m_repository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_repository.name;
|
||||
repo.url = url;
|
||||
repo.rev = rev;
|
||||
repo.hash = repohash;
|
||||
auto lastSlash = url.find_last_of('/');
|
||||
auto secondLastSlash = url.find_last_of('/', lastSlash - 1);
|
||||
repo.name = pManifest->m_repository.name.empty() ? url.substr(lastSlash + 1) : pManifest->m_repository.name;
|
||||
repo.author = url.substr(secondLastSlash + 1, lastSlash - secondLastSlash - 1);
|
||||
repo.url = url;
|
||||
repo.rev = rev;
|
||||
repo.hash = repohash;
|
||||
for (auto const& p : pManifest->m_plugins) {
|
||||
repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed});
|
||||
}
|
||||
|
|
@ -356,13 +360,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
if (!DataState::pluginRepoExists(urlOrName)) {
|
||||
bool CPluginManager::removePluginRepo(const SPluginRepoIdentifier identifier) {
|
||||
if (!DataState::pluginRepoExists(identifier)) {
|
||||
std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << Colors::YELLOW << "!" << Colors::RESET << Colors::RED << " removing a plugin repository: " << Colors::RESET << urlOrName << "\n "
|
||||
std::cout << Colors::YELLOW << "!" << Colors::RESET << Colors::RED << " removing a plugin repository: " << Colors::RESET << identifier.toString() << "\n "
|
||||
<< "Are you sure? [Y/n] ";
|
||||
std::fflush(stdout);
|
||||
std::string input;
|
||||
|
|
@ -373,7 +377,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
|||
return false;
|
||||
}
|
||||
|
||||
DataState::removePluginRepo(urlOrName);
|
||||
DataState::removePluginRepo(identifier);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -444,7 +448,6 @@ eHeadersErrors CPluginManager::headersValid() {
|
|||
}
|
||||
|
||||
bool CPluginManager::updateHeaders(bool force) {
|
||||
|
||||
DataState::ensureStateStoreExists();
|
||||
|
||||
const auto HLVER = getHyprlandVersion(false);
|
||||
|
|
@ -772,7 +775,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
|||
const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; });
|
||||
newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false});
|
||||
}
|
||||
DataState::removePluginRepo(newrepo.name);
|
||||
DataState::removePluginRepo(SPluginRepoIdentifier::fromName(newrepo.name));
|
||||
DataState::addNewPluginRepo(newrepo);
|
||||
|
||||
std::filesystem::remove_all(m_szWorkingPluginDirectory);
|
||||
|
|
@ -797,17 +800,23 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::enablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, true);
|
||||
bool CPluginManager::enablePlugin(const SPluginRepoIdentifier identifier) {
|
||||
bool ret = false;
|
||||
|
||||
switch (identifier.type) {
|
||||
case IDENTIFIER_NAME:
|
||||
case IDENTIFIER_AUTHOR_NAME: ret = DataState::setPluginEnabled(identifier, true); break;
|
||||
default: return false;
|
||||
}
|
||||
if (ret)
|
||||
std::println("{}", successString("Enabled {}", name));
|
||||
std::println("{}", successString("Enabled {}", identifier.name));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::disablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, false);
|
||||
bool CPluginManager::disablePlugin(const SPluginRepoIdentifier identifier) {
|
||||
bool ret = DataState::setPluginEnabled(identifier, false);
|
||||
if (ret)
|
||||
std::println("{}", successString("Disabled {}", name));
|
||||
std::println("{}", successString("Disabled {}", identifier.name));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -928,7 +937,7 @@ void CPluginManager::listAllPlugins() {
|
|||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
for (auto const& r : REPOS) {
|
||||
std::println("{}", infoString("Repository {}:", r.name));
|
||||
std::println("{}", infoString("Repository {} (by {}):", r.name, r.author));
|
||||
|
||||
for (auto const& p : r.plugins) {
|
||||
std::println(" │ Plugin {}", p.name);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "Plugin.hpp"
|
||||
|
||||
enum eHeadersErrors {
|
||||
HEADERS_OK = 0,
|
||||
|
|
@ -46,7 +48,7 @@ class CPluginManager {
|
|||
CPluginManager();
|
||||
|
||||
bool addNewPluginRepo(const std::string& url, const std::string& rev);
|
||||
bool removePluginRepo(const std::string& urlOrName);
|
||||
bool removePluginRepo(const SPluginRepoIdentifier identifier);
|
||||
|
||||
eHeadersErrors headersValid();
|
||||
bool updateHeaders(bool force = false);
|
||||
|
|
@ -54,8 +56,8 @@ class CPluginManager {
|
|||
|
||||
void listAllPlugins();
|
||||
|
||||
bool enablePlugin(const std::string& name);
|
||||
bool disablePlugin(const std::string& name);
|
||||
bool enablePlugin(const SPluginRepoIdentifier identifier);
|
||||
bool disablePlugin(const SPluginRepoIdentifier identifier);
|
||||
ePluginLoadStateReturn ensurePluginsLoadState(bool forceReload = false);
|
||||
|
||||
bool loadUnloadPlugin(const std::string& path, bool load);
|
||||
|
|
|
|||
|
|
@ -13,25 +13,25 @@ using namespace Hyprutils::Utils;
|
|||
|
||||
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┃
|
||||
┣ add [url] [git rev] → Install a new plugin repository from git. Git revision
|
||||
┃ is optional, when set, commit locks are ignored.
|
||||
┣ remove [url/name] → Remove an installed plugin repository.
|
||||
┣ enable [name] → Enable a plugin.
|
||||
┣ disable [name] → Disable a plugin.
|
||||
┣ update → Check and update all plugins if needed.
|
||||
┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
|
||||
┣ list → List all installed plugins.
|
||||
┣ purge-cache → Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
|
||||
┣ add <url> [git rev] → Install a new plugin repository from git. Git revision
|
||||
┃ is optional, when set, commit locks are ignored.
|
||||
┣ remove <url|name|author/name> → Remove an installed plugin repository.
|
||||
┣ enable <name|author/name> → Enable a plugin.
|
||||
┣ disable <name|author/name> → Disable a plugin.
|
||||
┣ update → Check and update all plugins if needed.
|
||||
┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
|
||||
┣ list → List all installed plugins.
|
||||
┣ purge-cache → Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
|
||||
┃
|
||||
┣ Flags:
|
||||
┃
|
||||
┣ --notify | -n → Send a hyprland notification confirming successful plugin load.
|
||||
┃ Warnings/Errors trigger notifications regardless of this flag.
|
||||
┣ --help | -h → Show this menu.
|
||||
┣ --verbose | -v → Enable too much logging.
|
||||
┣ --force | -f → Force an operation ignoring checks (e.g. update -f).
|
||||
┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources.
|
||||
┣ --hl-url | → Pass a custom hyprland source url.
|
||||
┣ --notify | -n → Send a hyprland notification confirming successful plugin load.
|
||||
┃ Warnings/Errors trigger notifications regardless of this flag.
|
||||
┣ --help | -h → Show this menu.
|
||||
┣ --verbose | -v → Enable too much logging.
|
||||
┣ --force | -f → Force an operation ignoring checks (e.g. update -f).
|
||||
┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources.
|
||||
┣ --hl-url | → Pass a custom hyprland source url.
|
||||
┗
|
||||
)#";
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
NSys::root::cacheSudo();
|
||||
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||
|
||||
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
|
||||
return g_pPluginManager->removePluginRepo(SPluginRepoIdentifier::fromString(command[1])) ? 0 : 1;
|
||||
} else if (command[0] == "update") {
|
||||
NSys::root::cacheSudo();
|
||||
CScopeGuard x([] { NSys::root::dropSudo(); });
|
||||
|
|
@ -160,7 +160,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->enablePlugin(command[1])) {
|
||||
if (!g_pPluginManager->enablePlugin(SPluginRepoIdentifier::fromString(command[1]))) {
|
||||
std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)"));
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -181,7 +181,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->disablePlugin(command[1])) {
|
||||
if (!g_pPluginManager->disablePlugin(SPluginRepoIdentifier::fromString(command[1]))) {
|
||||
std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)"));
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
cairo,
|
||||
epoll-shim,
|
||||
git,
|
||||
glaze,
|
||||
glaze-hyprland,
|
||||
gtest,
|
||||
hyprcursor,
|
||||
hyprgraphics,
|
||||
|
|
@ -143,7 +143,7 @@ in
|
|||
aquamarine
|
||||
cairo
|
||||
git
|
||||
glaze
|
||||
glaze-hyprland
|
||||
gtest
|
||||
hyprcursor
|
||||
hyprgraphics
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ in {
|
|||
inputs.hyprwayland-scanner.overlays.default
|
||||
inputs.hyprwire.overlays.default
|
||||
self.overlays.udis86
|
||||
self.overlays.glaze
|
||||
|
||||
# Hyprland packages themselves
|
||||
(final: _prev: let
|
||||
|
|
@ -110,4 +111,13 @@ in {
|
|||
patches = [];
|
||||
});
|
||||
};
|
||||
|
||||
# Even though glaze itself disables it by default, nixpkgs sets ENABLE_SSL set to true.
|
||||
# Since we don't include openssl, the build failes without the `enableSSL = false;` override
|
||||
glaze = final: prev: {
|
||||
glaze-hyprland = prev.glaze.override {
|
||||
enableSSL = false;
|
||||
enableInterop = false;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -894,7 +894,10 @@ bool CCompositor::monitorExists(PHLMONITOR pMonitor) {
|
|||
}
|
||||
|
||||
PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, PHLWINDOW pIgnoreWindow) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
if (!PMONITOR)
|
||||
return nullptr;
|
||||
|
||||
static auto PRESIZEONBORDER = CConfigValue<Hyprlang::INT>("general:resize_on_border");
|
||||
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
|
||||
static auto PBORDERGRABEXTEND = CConfigValue<Hyprlang::INT>("general:extend_border_grab_area");
|
||||
|
|
@ -993,8 +996,18 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
|
|||
const WORKSPACEID WSPID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID();
|
||||
const auto PWORKSPACE = getWorkspaceByID(WSPID);
|
||||
|
||||
if (PWORKSPACE->m_hasFullscreenWindow && !(properties & Desktop::View::SKIP_FULLSCREEN_PRIORITY) && !ONLY_PRIORITY)
|
||||
return PWORKSPACE->getFullscreenWindow();
|
||||
if (PWORKSPACE->m_hasFullscreenWindow && !(properties & Desktop::View::SKIP_FULLSCREEN_PRIORITY) && !ONLY_PRIORITY) {
|
||||
const auto FS_WINDOW = PWORKSPACE->getFullscreenWindow();
|
||||
|
||||
if (!FS_WINDOW)
|
||||
return nullptr;
|
||||
|
||||
// for maximized windows, don't return a window if we are not directly on it.
|
||||
if (FS_WINDOW->m_fullscreenState.internal != FSMODE_MAXIMIZED || FS_WINDOW->getWindowBoxUnified(properties).containsPoint(pos))
|
||||
return PWORKSPACE->getFullscreenWindow();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto found = floating(false);
|
||||
if (found)
|
||||
|
|
@ -1130,7 +1143,7 @@ PHLMONITOR CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) {
|
|||
SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) {
|
||||
for (auto const& lsl : monitor->m_layerSurfaceLayers | std::views::reverse) {
|
||||
for (auto const& ls : lsl | std::views::reverse) {
|
||||
if (!ls->visible() || ls->m_fadingOut)
|
||||
if (!ls->aliveAndVisible())
|
||||
continue;
|
||||
|
||||
auto SURFACEAT = ls->m_popupHead->at(pos, true);
|
||||
|
|
@ -1150,7 +1163,7 @@ SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, st
|
|||
bool aboveLockscreen) {
|
||||
|
||||
for (auto const& ls : *layerSurfaces | std::views::reverse) {
|
||||
if (!ls->visible() || ls->m_fadingOut || (aboveLockscreen && ls->m_ruleApplicator->aboveLock().valueOrDefault() != 2))
|
||||
if (!ls->aliveAndVisible() || (aboveLockscreen && ls->m_ruleApplicator->aboveLock().valueOrDefault() != 2))
|
||||
continue;
|
||||
|
||||
auto [surf, local] = ls->m_layerSurface->m_surface->at(pos - ls->m_geometry.pos(), true);
|
||||
|
|
@ -1380,6 +1393,9 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
|
|||
const auto WINDOWIDEALBB = pWindow->isFullscreen() ? CBox{PMONITOR->m_position, PMONITOR->m_size} : pWindow->getWindowIdealBoundingBoxIgnoreReserved();
|
||||
const auto PWORKSPACE = pWindow->m_workspace;
|
||||
|
||||
if (!PWORKSPACE)
|
||||
return nullptr; // ??
|
||||
|
||||
return getWindowInDirection(WINDOWIDEALBB, PWORKSPACE, dir, pWindow, pWindow->m_isFloating);
|
||||
}
|
||||
|
||||
|
|
@ -1621,12 +1637,12 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR
|
|||
const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point);
|
||||
|
||||
auto box = PMONITOR->logicalBox();
|
||||
if (VECNOTINRECT(point, box.x - 1, box.y - 1, box.w + 2, box.h + 2))
|
||||
if (VECNOTINRECT(point, box.x - 1, box.y - 1, box.x + box.w + 1, box.y + box.h + 1))
|
||||
return false;
|
||||
|
||||
PMONITOR->m_reservedArea.applyip(box);
|
||||
|
||||
return VECNOTINRECT(point, box.x, box.y, box.x, box.y);
|
||||
return VECNOTINRECT(point, box.x, box.y, box.x + box.w, box.y + box.h);
|
||||
}
|
||||
|
||||
CBox CCompositor::calculateX11WorkArea() {
|
||||
|
|
@ -2347,7 +2363,7 @@ PHLLS CCompositor::getLayerSurfaceFromSurface(SP<CWLSurfaceResource> pSurface) {
|
|||
std::pair<SP<CWLSurfaceResource>, bool> result = {pSurface, false};
|
||||
|
||||
for (auto const& ls : m_layers) {
|
||||
if (!ls->visible() || ls->m_fadingOut)
|
||||
if (!ls->aliveAndVisible())
|
||||
continue;
|
||||
|
||||
if (ls->m_layerSurface->m_surface == pSurface)
|
||||
|
|
|
|||
|
|
@ -1658,6 +1658,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
|||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:zoom_detached_camera",
|
||||
.description = "Detaches the camera from the mouse when zoomed in, only ever moving to keep the mouse in view",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "cursor:enable_hyprcursor",
|
||||
.description = "whether to enable hyprcursor support",
|
||||
|
|
|
|||
|
|
@ -734,6 +734,7 @@ CConfigManager::CConfigManager() {
|
|||
registerConfigVar("cursor:zoom_factor", {1.f});
|
||||
registerConfigVar("cursor:zoom_rigid", Hyprlang::INT{0});
|
||||
registerConfigVar("cursor:zoom_disable_aa", Hyprlang::INT{0});
|
||||
registerConfigVar("cursor:zoom_detached_camera", Hyprlang::INT{1});
|
||||
registerConfigVar("cursor:enable_hyprcursor", Hyprlang::INT{1});
|
||||
registerConfigVar("cursor:sync_gsettings_theme", Hyprlang::INT{1});
|
||||
registerConfigVar("cursor:hide_on_key_press", Hyprlang::INT{0});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ std::vector<SP<IView>> View::getViewsForWorkspace(PHLWORKSPACE ws) {
|
|||
std::vector<SP<IView>> views;
|
||||
|
||||
for (const auto& w : g_pCompositor->m_windows) {
|
||||
if (!w->visible() || w->m_workspace != ws)
|
||||
if (!w->aliveAndVisible() || w->m_workspace != ws)
|
||||
continue;
|
||||
|
||||
views.emplace_back(w);
|
||||
|
|
@ -38,7 +38,7 @@ std::vector<SP<IView>> View::getViewsForWorkspace(PHLWORKSPACE ws) {
|
|||
w->m_popupHead->breadthfirst(
|
||||
[&views](SP<CPopup> s, void* data) {
|
||||
auto surf = s->wlSurface();
|
||||
if (!surf || !s->visible())
|
||||
if (!surf || !s->aliveAndVisible())
|
||||
return;
|
||||
|
||||
views.emplace_back(surf->view());
|
||||
|
|
@ -48,7 +48,7 @@ std::vector<SP<IView>> View::getViewsForWorkspace(PHLWORKSPACE ws) {
|
|||
}
|
||||
|
||||
for (const auto& l : g_pCompositor->m_layers) {
|
||||
if (!l->visible() || l->m_monitor != ws->m_monitor)
|
||||
if (!l->aliveAndVisible() || l->m_monitor != ws->m_monitor)
|
||||
continue;
|
||||
|
||||
views.emplace_back(l);
|
||||
|
|
@ -56,7 +56,7 @@ std::vector<SP<IView>> View::getViewsForWorkspace(PHLWORKSPACE ws) {
|
|||
l->m_popupHead->breadthfirst(
|
||||
[&views](SP<CPopup> p, void* data) {
|
||||
auto surf = p->wlSurface();
|
||||
if (!surf || !p->visible())
|
||||
if (!surf || !p->aliveAndVisible())
|
||||
return;
|
||||
|
||||
views.emplace_back(surf->view());
|
||||
|
|
@ -65,7 +65,7 @@ std::vector<SP<IView>> View::getViewsForWorkspace(PHLWORKSPACE ws) {
|
|||
}
|
||||
|
||||
for (const auto& v : g_pCompositor->m_otherViews) {
|
||||
if (!v->visible() || !v->desktopComponent())
|
||||
if (!v->aliveAndVisible() || !v->desktopComponent())
|
||||
continue;
|
||||
|
||||
if (v->type() == VIEW_TYPE_LOCK_SCREEN) {
|
||||
|
|
|
|||
|
|
@ -93,13 +93,13 @@ namespace Desktop::View {
|
|||
inline bool validMapped(PHLLS l) {
|
||||
if (!valid(l))
|
||||
return false;
|
||||
return l->visible();
|
||||
return l->aliveAndVisible();
|
||||
}
|
||||
|
||||
inline bool validMapped(PHLLSREF l) {
|
||||
if (!valid(l))
|
||||
return false;
|
||||
return l->visible();
|
||||
return l->aliveAndVisible();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "View.hpp"
|
||||
#include "../../protocols/core/Compositor.hpp"
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::View;
|
||||
|
|
@ -14,3 +15,14 @@ IView::IView(SP<Desktop::View::CWLSurface> pWlSurface) : m_wlSurface(pWlSurface)
|
|||
SP<CWLSurfaceResource> IView::resource() const {
|
||||
return m_wlSurface ? m_wlSurface->resource() : nullptr;
|
||||
}
|
||||
|
||||
bool IView::aliveAndVisible() const {
|
||||
auto res = resource();
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
if (!res->m_mapped)
|
||||
return false;
|
||||
|
||||
return visible();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ namespace Desktop::View {
|
|||
|
||||
virtual SP<Desktop::View::CWLSurface> wlSurface() const;
|
||||
virtual SP<CWLSurfaceResource> resource() const;
|
||||
virtual bool aliveAndVisible() const;
|
||||
virtual eViewType type() const = 0;
|
||||
virtual bool visible() const = 0;
|
||||
virtual bool desktopComponent() const = 0;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ SP<CWLSurfaceResource> CWLSurface::resource() const {
|
|||
}
|
||||
|
||||
bool CWLSurface::small() const {
|
||||
if (!m_view || !m_view->visible() || m_view->type() != VIEW_TYPE_WINDOW || !exists())
|
||||
if (!m_view || !m_view->aliveAndVisible() || m_view->type() != VIEW_TYPE_WINDOW || !exists())
|
||||
return false;
|
||||
|
||||
if (!m_resource->m_current.texture)
|
||||
|
|
@ -51,7 +51,7 @@ bool CWLSurface::small() const {
|
|||
}
|
||||
|
||||
Vector2D CWLSurface::correctSmallVec() const {
|
||||
if (!m_view || !m_view->visible() || m_view->type() != VIEW_TYPE_WINDOW || !exists() || !small() || !m_fillIgnoreSmall)
|
||||
if (!m_view || !m_view->aliveAndVisible() || m_view->type() != VIEW_TYPE_WINDOW || !exists() || !small() || !m_fillIgnoreSmall)
|
||||
return {};
|
||||
|
||||
const auto SIZE = getViewporterCorrectedSize();
|
||||
|
|
@ -171,12 +171,6 @@ SP<CPointerConstraint> CWLSurface::constraint() const {
|
|||
return m_constraint.lock();
|
||||
}
|
||||
|
||||
bool CWLSurface::visible() {
|
||||
if (m_view)
|
||||
return m_view->visible();
|
||||
return true; // non-desktop, we don't know much.
|
||||
}
|
||||
|
||||
SP<Desktop::View::CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
|
||||
if (!pSurface)
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ namespace Desktop::View {
|
|||
Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords
|
||||
Vector2D getViewporterCorrectedSize() const;
|
||||
CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
|
||||
bool visible();
|
||||
bool keyboardFocusable() const;
|
||||
|
||||
SP<IView> view() const;
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ eViewType CWindow::type() const {
|
|||
}
|
||||
|
||||
bool CWindow::visible() const {
|
||||
return m_isMapped && !m_hidden && m_wlSurface && m_wlSurface->resource();
|
||||
return !m_hidden && ((m_isMapped && m_wlSurface && m_wlSurface->resource()) || (m_fadingOut && m_alpha->value() != 0.F));
|
||||
}
|
||||
|
||||
std::optional<CBox> CWindow::logicalBox() const {
|
||||
|
|
@ -639,14 +639,13 @@ void CWindow::onMap() {
|
|||
}
|
||||
|
||||
void CWindow::onBorderAngleAnimEnd(WP<CBaseAnimatedVariable> pav) {
|
||||
const auto PAV = pav.lock();
|
||||
if (!PAV)
|
||||
if (!pav)
|
||||
return;
|
||||
|
||||
if (PAV->getStyle() != "loop" || !PAV->enabled())
|
||||
if (pav->getStyle() != "loop" || !pav->enabled())
|
||||
return;
|
||||
|
||||
const auto PANIMVAR = dc<CAnimatedVariable<float>*>(PAV.get());
|
||||
const auto PANIMVAR = dc<CAnimatedVariable<float>*>(pav.get());
|
||||
|
||||
PANIMVAR->setCallbackOnEnd(nullptr); // we remove the callback here because otherwise setvalueandwarp will recurse this
|
||||
|
||||
|
|
@ -1197,14 +1196,19 @@ int CWindow::surfacesCount() {
|
|||
return no;
|
||||
}
|
||||
|
||||
void CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize) {
|
||||
bool CWindow::clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize) {
|
||||
const Vector2D REALSIZE = m_realSize->goal();
|
||||
const Vector2D MAX = isFullscreen() ? Vector2D{INFINITY, INFINITY} : maxSize.value_or(Vector2D{INFINITY, INFINITY});
|
||||
const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), MAX);
|
||||
const Vector2D DELTA = REALSIZE - NEWSIZE;
|
||||
const bool changed = !(NEWSIZE == REALSIZE);
|
||||
|
||||
*m_realPosition = m_realPosition->goal() + DELTA / 2.0;
|
||||
*m_realSize = NEWSIZE;
|
||||
if (changed) {
|
||||
const Vector2D DELTA = REALSIZE - NEWSIZE;
|
||||
*m_realPosition = m_realPosition->goal() + DELTA / 2.0;
|
||||
*m_realSize = NEWSIZE;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool CWindow::isFullscreen() {
|
||||
|
|
@ -1907,16 +1911,14 @@ std::optional<Vector2D> CWindow::calculateExpression(const std::string& s) {
|
|||
}
|
||||
|
||||
static void setVector2DAnimToMove(WP<CBaseAnimatedVariable> pav) {
|
||||
const auto PAV = pav.lock();
|
||||
if (!PAV)
|
||||
if (!pav)
|
||||
return;
|
||||
|
||||
CAnimatedVariable<Vector2D>* animvar = dc<CAnimatedVariable<Vector2D>*>(PAV.get());
|
||||
CAnimatedVariable<Vector2D>* animvar = dc<CAnimatedVariable<Vector2D>*>(pav.get());
|
||||
animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
|
||||
|
||||
const auto PHLWINDOW = animvar->m_Context.pWindow.lock();
|
||||
if (PHLWINDOW)
|
||||
PHLWINDOW->m_animatingIn = false;
|
||||
if (animvar->m_Context.pWindow)
|
||||
animvar->m_Context.pWindow->m_animatingIn = false;
|
||||
}
|
||||
|
||||
void CWindow::mapWindow() {
|
||||
|
|
@ -2554,8 +2556,8 @@ void CWindow::commitWindow() {
|
|||
const auto MINSIZE = m_xdgSurface->m_toplevel->layoutMinSize();
|
||||
const auto MAXSIZE = m_xdgSurface->m_toplevel->layoutMaxSize();
|
||||
|
||||
clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional<Vector2D>{MAXSIZE} : std::nullopt);
|
||||
g_pHyprRenderer->damageWindow(m_self.lock());
|
||||
if (clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional<Vector2D>{MAXSIZE} : std::nullopt))
|
||||
g_pHyprRenderer->damageWindow(m_self.lock());
|
||||
}
|
||||
|
||||
if (!m_workspace->m_visible)
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ namespace Desktop::View {
|
|||
bool onSpecialWorkspace();
|
||||
void activate(bool force = false);
|
||||
int surfacesCount();
|
||||
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
|
||||
bool clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
|
||||
bool isFullscreen();
|
||||
bool isEffectiveInternalFSMode(const eFullscreenMode) const;
|
||||
int getRealBorderSize() const;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ template <Animable VarType>
|
|||
using CAnimatedVariable = Hyprutils::Animation::CGenericAnimatedVariable<VarType, SAnimationContext>;
|
||||
|
||||
template <Animable VarType>
|
||||
using PHLANIMVAR = SP<CAnimatedVariable<VarType>>;
|
||||
using PHLANIMVAR = UP<CAnimatedVariable<VarType>>;
|
||||
|
||||
template <Animable VarType>
|
||||
using PHLANIMVARREF = WP<CAnimatedVariable<VarType>>;
|
||||
|
|
|
|||
|
|
@ -147,6 +147,10 @@ bool CAsyncDialogBox::isRunning() const {
|
|||
return m_readEventSource;
|
||||
}
|
||||
|
||||
pid_t CAsyncDialogBox::getPID() const {
|
||||
return m_dialogPid;
|
||||
}
|
||||
|
||||
SP<CAsyncDialogBox> CAsyncDialogBox::lockSelf() {
|
||||
return m_selfWeakReference.lock();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class CAsyncDialogBox {
|
|||
SP<CPromise<std::string>> open();
|
||||
void kill();
|
||||
bool isRunning() const;
|
||||
pid_t getPID() const;
|
||||
|
||||
SP<CAsyncDialogBox> lockSelf();
|
||||
|
||||
|
|
@ -51,4 +52,4 @@ class CAsyncDialogBox {
|
|||
// WARNING: cyclic reference. This will be removed once the event source is removed to avoid dangling pointers
|
||||
SP<CAsyncDialogBox> m_selfReference;
|
||||
WP<CAsyncDialogBox> m_selfWeakReference;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1799,8 +1799,8 @@ uint16_t CMonitor::isDSBlocked(bool full) {
|
|||
return reasons;
|
||||
}
|
||||
|
||||
if (needsCM() && *PNONSHADER != CM_NS_IGNORE && !canNoShaderCM() && (!inHDR() || (PSURFACE->m_colorManagement.valid() && PSURFACE->m_colorManagement->isWindowsScRGB())) &&
|
||||
*PPASS != 1)
|
||||
const bool surfaceIsHDR = PSURFACE->m_colorManagement.valid() && (PSURFACE->m_colorManagement->isHDR() || PSURFACE->m_colorManagement->isWindowsScRGB());
|
||||
if (needsCM() && *PNONSHADER != CM_NS_IGNORE && !canNoShaderCM() && ((inHDR() && (*PPASS == 0 || !surfaceIsHDR)) || (!inHDR() && (*PPASS != 1 || surfaceIsHDR))))
|
||||
reasons |= DS_BLOCK_CM;
|
||||
|
||||
return reasons;
|
||||
|
|
@ -2065,10 +2065,13 @@ bool CMonitor::canNoShaderCM() {
|
|||
if (SRC_DESC->icc.fd >= 0 || m_imageDescription.icc.fd >= 0)
|
||||
return false; // no ICC support
|
||||
|
||||
static auto PSDREOTF = CConfigValue<Hyprlang::INT>("render:cm_sdr_eotf");
|
||||
// only primaries differ
|
||||
if (SRC_DESC->transferFunction == m_imageDescription.transferFunction && SRC_DESC->transferFunctionPower == m_imageDescription.transferFunctionPower &&
|
||||
(!inHDR() || SRC_DESC->luminances == m_imageDescription.luminances) && SRC_DESC->masteringLuminances == m_imageDescription.masteringLuminances &&
|
||||
SRC_DESC->maxCLL == m_imageDescription.maxCLL && SRC_DESC->maxFALL == m_imageDescription.maxFALL)
|
||||
if ((SRC_DESC->transferFunction == m_imageDescription.transferFunction ||
|
||||
(*PSDREOTF == 2 && SRC_DESC->transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB &&
|
||||
m_imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22)) &&
|
||||
SRC_DESC->transferFunctionPower == m_imageDescription.transferFunctionPower && (!inHDR() || SRC_DESC->luminances == m_imageDescription.luminances) &&
|
||||
SRC_DESC->masteringLuminances == m_imageDescription.masteringLuminances && SRC_DESC->maxCLL == m_imageDescription.maxCLL && SRC_DESC->maxFALL == m_imageDescription.maxFALL)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "CMType.hpp"
|
||||
|
||||
#include <xf86drmMode.h>
|
||||
#include "MonitorZoomController.hpp"
|
||||
#include "time/Timer.hpp"
|
||||
#include "math/Math.hpp"
|
||||
#include "../desktop/reserved/ReservedArea.hpp"
|
||||
|
|
@ -130,6 +131,8 @@ class CMonitor {
|
|||
uint32_t m_drmFormat = DRM_FORMAT_INVALID;
|
||||
uint32_t m_prevDrmFormat = DRM_FORMAT_INVALID;
|
||||
|
||||
CMonitorZoomController m_zoomController;
|
||||
|
||||
bool m_dpmsStatus = true;
|
||||
bool m_vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool m_enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
|
|
|
|||
97
src/helpers/MonitorZoomController.cpp
Normal file
97
src/helpers/MonitorZoomController.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#include "MonitorZoomController.hpp"
|
||||
|
||||
#include <hyprlang.hpp>
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
#include "../render/OpenGL.hpp"
|
||||
#include "desktop/DesktopTypes.hpp"
|
||||
#include "render/Renderer.hpp"
|
||||
|
||||
void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const SCurrentRenderData& m_renderData) {
|
||||
const auto m = m_renderData.pMonitor;
|
||||
auto monbox = CBox(0, 0, m->m_size.x, m->m_size.y);
|
||||
const auto ZOOM = m_renderData.mouseZoomFactor;
|
||||
const auto MOUSE = g_pInputManager->getMouseCoordsInternal() - m->m_position;
|
||||
|
||||
if (m_lastZoomLevel != ZOOM) {
|
||||
if (m_resetCameraState) {
|
||||
m_resetCameraState = false;
|
||||
m_camera = CBox(0, 0, m->m_size.x, m->m_size.y);
|
||||
m_lastZoomLevel = 1.0f;
|
||||
}
|
||||
const CBox old = m_camera;
|
||||
|
||||
// mouse normalized inside screen (0..1)
|
||||
const float mx = MOUSE.x / m->m_size.x;
|
||||
const float my = MOUSE.y / m->m_size.y;
|
||||
// world-space point under the cursor before zoom
|
||||
const float mouseWorldX = old.x + (mx * old.w);
|
||||
const float mouseWorldY = old.y + (my * old.h);
|
||||
|
||||
const auto CAMERAW = monbox.w / ZOOM;
|
||||
const auto CAMERAH = monbox.h / ZOOM;
|
||||
|
||||
// compute new top-left so the same world point stays under the cursor
|
||||
const float newX = mouseWorldX - (mx * CAMERAW);
|
||||
const float newY = mouseWorldY - (my * CAMERAH);
|
||||
|
||||
m_camera = CBox(newX, newY, CAMERAW, CAMERAH);
|
||||
// Detect if this zoom would've caused jerk to keep mouse in view and disable edges if so
|
||||
if (!m_camera.copy().scaleFromCenter(.9).containsPoint(MOUSE))
|
||||
m_padCamEdges = false;
|
||||
m_lastZoomLevel = ZOOM;
|
||||
}
|
||||
|
||||
// Keep mouse inside cameraview
|
||||
auto smallerbox = m_camera;
|
||||
// Prevent zoom step from causing us to jerk to keep mouse in padded camera view,
|
||||
// but let us switch to the padded camera once the mouse moves into the safe area
|
||||
if (!m_padCamEdges)
|
||||
if (smallerbox.copy().scaleFromCenter(.9).containsPoint(MOUSE))
|
||||
m_padCamEdges = true;
|
||||
if (m_padCamEdges)
|
||||
smallerbox.scaleFromCenter(.9);
|
||||
if (!smallerbox.containsPoint(MOUSE)) {
|
||||
if (MOUSE.x < smallerbox.x)
|
||||
m_camera.x -= smallerbox.x - MOUSE.x;
|
||||
if (MOUSE.y < smallerbox.y)
|
||||
m_camera.y -= smallerbox.y - MOUSE.y;
|
||||
if (MOUSE.y > smallerbox.y + smallerbox.h)
|
||||
m_camera.y += MOUSE.y - (smallerbox.y + smallerbox.h);
|
||||
if (MOUSE.x > smallerbox.x + smallerbox.w)
|
||||
m_camera.x += MOUSE.x - (smallerbox.x + smallerbox.w);
|
||||
}
|
||||
|
||||
auto z = ZOOM * m->m_scale;
|
||||
monbox.scale(z).translate(-m_camera.pos() * z);
|
||||
|
||||
result = monbox;
|
||||
}
|
||||
|
||||
void CMonitorZoomController::applyZoomTransform(CBox& monbox, const SCurrentRenderData& m_renderData) {
|
||||
static auto PZOOMRIGID = CConfigValue<Hyprlang::INT>("cursor:zoom_rigid");
|
||||
static auto PZOOMDETACHEDCAMERA = CConfigValue<Hyprlang::INT>("cursor:zoom_detached_camera");
|
||||
const auto ZOOM = m_renderData.mouseZoomFactor;
|
||||
|
||||
if (ZOOM == 1.0f)
|
||||
return;
|
||||
|
||||
const auto m = m_renderData.pMonitor;
|
||||
const auto ORIGINAL = monbox;
|
||||
const auto INITANIM = m->m_zoomAnimProgress->value() != 1.0;
|
||||
|
||||
if (*PZOOMDETACHEDCAMERA && !INITANIM)
|
||||
zoomWithDetachedCamera(monbox, m_renderData);
|
||||
else {
|
||||
const auto ZOOMCENTER = m_renderData.mouseZoomUseMouse ? (g_pInputManager->getMouseCoordsInternal() - m->m_position) * m->m_scale : m->m_transformedSize / 2.f;
|
||||
|
||||
monbox.translate(-ZOOMCENTER).scale(ZOOM).translate(*PZOOMRIGID ? m->m_transformedSize / 2.0 : ZOOMCENTER);
|
||||
}
|
||||
|
||||
monbox.x = std::min(monbox.x, 0.0);
|
||||
monbox.y = std::min(monbox.y, 0.0);
|
||||
if (monbox.x + monbox.width < ORIGINAL.w)
|
||||
monbox.x = ORIGINAL.w - monbox.width;
|
||||
if (monbox.y + monbox.height < ORIGINAL.h)
|
||||
monbox.y = ORIGINAL.h - monbox.height;
|
||||
}
|
||||
19
src/helpers/MonitorZoomController.hpp
Normal file
19
src/helpers/MonitorZoomController.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "./math/Math.hpp"
|
||||
|
||||
struct SCurrentRenderData;
|
||||
|
||||
class CMonitorZoomController {
|
||||
public:
|
||||
bool m_resetCameraState = true;
|
||||
|
||||
void applyZoomTransform(CBox& monbox, const SCurrentRenderData& m_renderData);
|
||||
|
||||
private:
|
||||
void zoomWithDetachedCamera(CBox& result, const SCurrentRenderData& m_renderData);
|
||||
|
||||
CBox m_camera;
|
||||
float m_lastZoomLevel = 1.0f;
|
||||
bool m_padCamEdges = true;
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "ANRManager.hpp"
|
||||
|
||||
#include "../helpers/fs/FsUtils.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
|
@ -29,6 +30,10 @@ CANRManager::CANRManager() {
|
|||
auto window = std::any_cast<PHLWINDOW>(data);
|
||||
|
||||
for (const auto& d : m_data) {
|
||||
// Window is ANR dialog
|
||||
if (d->isRunning() && d->dialogBox->getPID() == window->getPID())
|
||||
return;
|
||||
|
||||
if (d->fitsWindow(window))
|
||||
return;
|
||||
}
|
||||
|
|
@ -84,7 +89,7 @@ void CANRManager::onTick() {
|
|||
|
||||
if (data->missedResponses >= *PANRTHRESHOLD) {
|
||||
if (!data->isRunning() && !data->dialogSaidWait) {
|
||||
data->runDialog(firstWindow->m_title, firstWindow->m_class, data->getPid());
|
||||
data->runDialog(firstWindow->m_title, firstWindow->m_class, data->getPID());
|
||||
|
||||
for (const auto& w : g_pCompositor->m_windows) {
|
||||
if (!w->m_isMapped)
|
||||
|
|
@ -240,7 +245,7 @@ bool CANRManager::SANRData::isDefunct() const {
|
|||
return xdgBase.expired() && xwaylandSurface.expired();
|
||||
}
|
||||
|
||||
pid_t CANRManager::SANRData::getPid() const {
|
||||
pid_t CANRManager::SANRData::getPID() const {
|
||||
if (xdgBase) {
|
||||
pid_t pid = 0;
|
||||
wl_client_get_credentials(xdgBase->client(), &pid, nullptr, nullptr);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class CANRManager {
|
|||
void killDialog();
|
||||
bool isDefunct() const;
|
||||
bool fitsWindow(PHLWINDOW pWindow) const;
|
||||
pid_t getPid() const;
|
||||
pid_t getPID() const;
|
||||
void ping();
|
||||
};
|
||||
|
||||
|
|
@ -57,4 +57,4 @@ class CANRManager {
|
|||
std::vector<SP<SANRData>> m_data;
|
||||
};
|
||||
|
||||
inline UP<CANRManager> g_pANRManager;
|
||||
inline UP<CANRManager> g_pANRManager;
|
||||
|
|
|
|||
|
|
@ -1487,7 +1487,7 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) {
|
|||
}
|
||||
|
||||
const auto PLASTWINDOW = Desktop::focusState()->window();
|
||||
if (!PLASTWINDOW) {
|
||||
if (!PLASTWINDOW || !PLASTWINDOW->aliveAndVisible()) {
|
||||
if (*PMONITORFALLBACK)
|
||||
tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg));
|
||||
|
||||
|
|
|
|||
|
|
@ -209,8 +209,7 @@ void CHyprAnimationManager::tick() {
|
|||
|
||||
static auto PANIMENABLED = CConfigValue<Hyprlang::INT>("animations:enabled");
|
||||
|
||||
for (size_t i = 0; i < m_vActiveAnimatedVariables.size(); i++) {
|
||||
const auto PAV = m_vActiveAnimatedVariables[i].lock();
|
||||
for (const auto& PAV : m_vActiveAnimatedVariables) {
|
||||
if (!PAV)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,13 +22,11 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager {
|
|||
template <Animable VarType>
|
||||
void createAnimation(const VarType& v, PHLANIMVAR<VarType>& pav, SP<SAnimationPropertyConfig> pConfig, eAVarDamagePolicy policy) {
|
||||
constexpr const eAnimatedVarType EAVTYPE = typeToeAnimatedVarType<VarType>;
|
||||
const auto PAV = makeShared<CAnimatedVariable<VarType>>();
|
||||
pav = makeUnique<CAnimatedVariable<VarType>>();
|
||||
|
||||
PAV->create(EAVTYPE, sc<Hyprutils::Animation::CAnimationManager*>(this), PAV, v);
|
||||
PAV->setConfig(pConfig);
|
||||
PAV->m_Context.eDamagePolicy = policy;
|
||||
|
||||
pav = std::move(PAV);
|
||||
pav->create2(EAVTYPE, sc<Hyprutils::Animation::CAnimationManager*>(this), pav, v);
|
||||
pav->setConfig(pConfig);
|
||||
pav->m_Context.eDamagePolicy = policy;
|
||||
}
|
||||
|
||||
template <Animable VarType>
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ void CInputManager::recheckIdleInhibitorStatus() {
|
|||
|
||||
auto WLSurface = Desktop::View::CWLSurface::fromResource(ii->inhibitor->m_surface.lock());
|
||||
|
||||
if (!WLSurface)
|
||||
if (!WLSurface || !WLSurface->view())
|
||||
continue;
|
||||
|
||||
if (WLSurface->visible()) {
|
||||
if (WLSurface->view()->aliveAndVisible()) {
|
||||
PROTO::idle->setInhibit(true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -85,10 +85,10 @@ bool CInputManager::isWindowInhibiting(const PHLWINDOW& w, bool onlyHl) {
|
|||
|
||||
auto WLSurface = Desktop::View::CWLSurface::fromResource(surf);
|
||||
|
||||
if (!WLSurface)
|
||||
if (!WLSurface || !WLSurface->view())
|
||||
return;
|
||||
|
||||
if (WLSurface->visible())
|
||||
if (WLSurface->view()->aliveAndVisible())
|
||||
*sc<bool*>(data) = true;
|
||||
},
|
||||
&isInhibiting);
|
||||
|
|
|
|||
|
|
@ -298,10 +298,17 @@ void CWLDataDeviceResource::sendDataOffer(SP<IDataOffer> offer) {
|
|||
void CWLDataDeviceResource::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<IDataOffer> offer) {
|
||||
if (const auto WL = offer->getWayland(); WL)
|
||||
m_resource->sendEnterRaw(serial, surf->getResource()->resource(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), WL->m_resource->resource());
|
||||
|
||||
m_entered = surf;
|
||||
|
||||
// FIXME: X11
|
||||
}
|
||||
|
||||
void CWLDataDeviceResource::sendLeave() {
|
||||
if (!m_entered)
|
||||
return;
|
||||
|
||||
m_entered.reset();
|
||||
m_resource->sendLeave();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,8 +111,10 @@ class CWLDataDeviceResource : public IDataDevice {
|
|||
WP<CWLDataDeviceResource> m_self;
|
||||
|
||||
private:
|
||||
SP<CWlDataDevice> m_resource;
|
||||
wl_client* m_client = nullptr;
|
||||
SP<CWlDataDevice> m_resource;
|
||||
wl_client* m_client = nullptr;
|
||||
|
||||
WP<CWLSurfaceResource> m_entered;
|
||||
|
||||
friend class CWLDataDeviceProtocol;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -849,7 +849,6 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb
|
|||
}
|
||||
|
||||
void CHyprOpenGLImpl::end() {
|
||||
static auto PZOOMRIGID = CConfigValue<Hyprlang::INT>("cursor:zoom_rigid");
|
||||
static auto PZOOMDISABLEAA = CConfigValue<Hyprlang::INT>("cursor:zoom_disable_aa");
|
||||
|
||||
TRACY_GPU_ZONE("RenderEnd");
|
||||
|
|
@ -861,20 +860,9 @@ void CHyprOpenGLImpl::end() {
|
|||
|
||||
CBox monbox = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y};
|
||||
|
||||
if (m_renderData.mouseZoomFactor != 1.f) {
|
||||
const auto ZOOMCENTER = m_renderData.mouseZoomUseMouse ?
|
||||
(g_pInputManager->getMouseCoordsInternal() - m_renderData.pMonitor->m_position) * m_renderData.pMonitor->m_scale :
|
||||
m_renderData.pMonitor->m_transformedSize / 2.f;
|
||||
|
||||
monbox.translate(-ZOOMCENTER).scale(m_renderData.mouseZoomFactor).translate(*PZOOMRIGID ? m_renderData.pMonitor->m_transformedSize / 2.0 : ZOOMCENTER);
|
||||
|
||||
monbox.x = std::min(monbox.x, 0.0);
|
||||
monbox.y = std::min(monbox.y, 0.0);
|
||||
if (monbox.x + monbox.width < m_renderData.pMonitor->m_transformedSize.x)
|
||||
monbox.x = m_renderData.pMonitor->m_transformedSize.x - monbox.width;
|
||||
if (monbox.y + monbox.height < m_renderData.pMonitor->m_transformedSize.y)
|
||||
monbox.y = m_renderData.pMonitor->m_transformedSize.y - monbox.height;
|
||||
}
|
||||
if (g_pHyprRenderer->m_renderMode == RENDER_MODE_NORMAL && m_renderData.mouseZoomFactor == 1.0f)
|
||||
m_renderData.pMonitor->m_zoomController.m_resetCameraState = true;
|
||||
m_renderData.pMonitor->m_zoomController.applyZoomTransform(monbox, m_renderData);
|
||||
|
||||
m_applyFinalShader = !m_renderData.blockScreenShader;
|
||||
if (m_renderData.mouseZoomUseMouse && *PZOOMDISABLEAA)
|
||||
|
|
@ -1715,7 +1703,9 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
|
|||
const bool skipCM = !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */
|
||||
|| m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
|
||||
|| (imageDescription == m_renderData.pMonitor->m_imageDescription && !data.cmBackToSRGB) /* Source and target have the same image description */
|
||||
|| (((*PPASS && canPassHDRSurface) || (*PPASS == 1 && !isHDRSurface)) && m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
|
||||
|| (((*PPASS && canPassHDRSurface) ||
|
||||
(*PPASS == 1 && !isHDRSurface && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR_EDID)) &&
|
||||
m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
|
||||
|
||||
if (!skipCM && !usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX))
|
||||
shader = &m_shaders->m_shCM;
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ class CHyprOpenGLImpl {
|
|||
GLsizei height = 0;
|
||||
} m_lastViewport;
|
||||
|
||||
std::array<bool, CAP_STATUS_END> m_capStatus;
|
||||
std::array<bool, CAP_STATUS_END> m_capStatus = {};
|
||||
|
||||
std::vector<SDRMFormat> m_drmFormats;
|
||||
bool m_hasModifiers = false;
|
||||
|
|
|
|||
|
|
@ -684,8 +684,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
|
|||
return;
|
||||
}
|
||||
|
||||
if (!popup->visible())
|
||||
if (!popup->aliveAndVisible())
|
||||
return;
|
||||
|
||||
const auto pos = popup->coordsRelativeToParent();
|
||||
const Vector2D oldPos = renderdata.pos;
|
||||
renderdata.pos += pos;
|
||||
|
|
@ -802,7 +803,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, const Time::s
|
|||
if (popups) {
|
||||
pLayer->m_popupHead->breadthfirst(
|
||||
[this, &renderdata](WP<Desktop::View::CPopup> popup, void* data) {
|
||||
if (!popup->visible())
|
||||
if (!popup->aliveAndVisible())
|
||||
return;
|
||||
|
||||
const auto SURF = popup->wlSurface()->resource();
|
||||
|
|
@ -1708,7 +1709,7 @@ void CHyprRenderer::renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace
|
|||
|
||||
void CHyprRenderer::sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now) {
|
||||
for (const auto& view : Desktop::View::getViewsForWorkspace(pWorkspace)) {
|
||||
if (!view->visible())
|
||||
if (!view->aliveAndVisible())
|
||||
continue;
|
||||
|
||||
view->wlSurface()->resource()->frame(now);
|
||||
|
|
@ -2505,7 +2506,7 @@ void CHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) {
|
|||
if (!PMONITOR || !PMONITOR->m_output || PMONITOR->m_pixelSize.x <= 0 || PMONITOR->m_pixelSize.y <= 0)
|
||||
return;
|
||||
|
||||
if (!popup->visible())
|
||||
if (!popup->aliveAndVisible())
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "renderer: making a snapshot of {:x}", rc<uintptr_t>(popup.get()));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue