Merge branch 'main' of https://github.com/hyprwm/Hyprland into move-center-override

This commit is contained in:
lichie 2025-12-14 18:17:12 -08:00
commit c051ceb6d2
40 changed files with 429 additions and 159 deletions

View file

@ -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

View file

@ -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})

View file

@ -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);

View file

@ -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();
};
};

View 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;
}

View file

@ -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;
};

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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;
};
};
}

View file

@ -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)

View file

@ -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",

View file

@ -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});

View file

@ -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) {

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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>>;

View file

@ -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();
}

View file

@ -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;
};
};

View file

@ -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;

View file

@ -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.

View 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;
}

View 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;
};

View file

@ -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);

View file

@ -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;

View file

@ -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));

View file

@ -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;

View file

@ -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>

View file

@ -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);

View file

@ -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();
}

View file

@ -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;
};

View file

@ -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;

View file

@ -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;

View file

@ -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()));