mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-09-05 19:08:18 +00:00
internal: Solitary clients with single subsurface & verbose solitary/tearing/DS checks (#11228)
Adds more verbose checks for various conditional rendering mechanisms
This commit is contained in:
4
Makefile
4
Makefile
@@ -92,3 +92,7 @@ asan:
|
||||
@echo "Hyprland done"
|
||||
|
||||
ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf
|
||||
|
||||
test:
|
||||
$(MAKE) debug
|
||||
./build/hyprtester/hyprtester -c hyprtester/test.conf -b ./build/Hyprland -p hyprtester/plugin/hyprtestplugin.so
|
||||
|
@@ -45,7 +45,7 @@ namespace Colors {
|
||||
|
||||
#define EXPECT_CONTAINS(haystack, needle) \
|
||||
if (const auto EXPECTED = needle; !std::string{haystack}.contains(EXPECTED)) { \
|
||||
NLog::log("{}Failed: {}{} should contain {} but doesn't. Source: {}@{}. Haystack is:\n{}", Colors::RED, Colors::RESET, #haystack, EXPECTED, __FILE__, __LINE__, \
|
||||
NLog::log("{}Failed: {}{} should contain {} but doesn't. Source: {}@{}. Haystack is:\n{}", Colors::RED, Colors::RESET, #haystack, #needle, __FILE__, __LINE__, \
|
||||
std::string{haystack}); \
|
||||
ret = 1; \
|
||||
TESTS_FAILED++; \
|
||||
|
@@ -168,6 +168,7 @@ static bool test() {
|
||||
|
||||
NLog::log("{}Reloading the config", Colors::YELLOW);
|
||||
OK(getFromSocket("/reload"));
|
||||
OK(getFromSocket("/dispatch workspace 1"));
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
76
hyprtester/src/tests/main/solitary.cpp
Normal file
76
hyprtester/src/tests/main/solitary.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "tests.hpp"
|
||||
#include "../../shared.hpp"
|
||||
#include "../../hyprctlCompat.hpp"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
#include "../shared.hpp"
|
||||
|
||||
static int ret = 0;
|
||||
|
||||
using namespace Hyprutils::OS;
|
||||
using namespace Hyprutils::Memory;
|
||||
|
||||
#define UP CUniquePointer
|
||||
#define SP CSharedPointer
|
||||
|
||||
static bool test() {
|
||||
NLog::log("{}Testing solitary clients", Colors::GREEN);
|
||||
|
||||
OK(getFromSocket("/keyword general:allow_tearing false"));
|
||||
OK(getFromSocket("/keyword render:direct_scanout 0"));
|
||||
OK(getFromSocket("/keyword cursor:no_hardware_cursors 1"));
|
||||
NLog::log("{}Expecting blocked solitary/DS/tearing", Colors::YELLOW);
|
||||
{
|
||||
auto str = getFromSocket("/monitors");
|
||||
EXPECT_CONTAINS(str, "solitary: 0\n");
|
||||
EXPECT_CONTAINS(str, "solitaryBlockedBy: windowed mode,missing candidate");
|
||||
EXPECT_CONTAINS(str, "activelyTearing: false");
|
||||
EXPECT_CONTAINS(str, "tearingBlockedBy: next frame is not torn,user settings,not supported by monitor,missing candidate");
|
||||
EXPECT_CONTAINS(str, "directScanoutTo: 0\n");
|
||||
EXPECT_CONTAINS(str, "directScanoutBlockedBy: user settings,software renders/cursors,missing candidate");
|
||||
}
|
||||
|
||||
// FIXME: need a reliable client with solitary opaque surface in fullscreen. kitty doesn't work all the time
|
||||
// NLog::log("{}Spawning kittyProcA", Colors::YELLOW);
|
||||
// auto kittyProcA = Tests::spawnKitty();
|
||||
|
||||
// if (!kittyProcA) {
|
||||
// NLog::log("{}Error: kitty did not spawn", Colors::RED);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// OK(getFromSocket("/keyword general:allow_tearing true"));
|
||||
// OK(getFromSocket("/keyword render:direct_scanout 1"));
|
||||
// NLog::log("{}", getFromSocket("/clients"));
|
||||
// OK(getFromSocket("/dispatch fullscreen"));
|
||||
// NLog::log("{}", getFromSocket("/clients"));
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
// NLog::log("{}Expecting kitty to almost pass for solitary/DS/tearing", Colors::YELLOW);
|
||||
// {
|
||||
// auto str = getFromSocket("/monitors");
|
||||
// EXPECT_NOT_CONTAINS(str, "solitary: 0\n");
|
||||
// EXPECT_CONTAINS(str, "solitaryBlockedBy: null");
|
||||
// EXPECT_CONTAINS(str, "activelyTearing: false");
|
||||
// EXPECT_CONTAINS(str, "tearingBlockedBy: next frame is not torn,not supported by monitor,window settings");
|
||||
// }
|
||||
|
||||
// OK(getFromSocket("/dispatch setprop active immediate 1"));
|
||||
// NLog::log("{}Expecting kitty to almost pass for tearing", Colors::YELLOW);
|
||||
// {
|
||||
// auto str = getFromSocket("/monitors");
|
||||
// EXPECT_CONTAINS(str, "tearingBlockedBy: next frame is not torn,not supported by monitor\n");
|
||||
// }
|
||||
|
||||
// // kill all
|
||||
// NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||
// Tests::killAllWindows();
|
||||
|
||||
NLog::log("{}Reloading the config", Colors::YELLOW);
|
||||
OK(getFromSocket("/reload"));
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
REGISTER_TEST_FN(test)
|
@@ -2400,8 +2400,11 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS
|
||||
|
||||
// send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't.
|
||||
// ignore if DS is disabled.
|
||||
if (*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && PWINDOW->getContentType() == CONTENT_TYPE_GAME))
|
||||
g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_wlSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->m_self.lock() : nullptr);
|
||||
if (*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && PWINDOW->getContentType() == CONTENT_TYPE_GAME)) {
|
||||
auto surf = PWINDOW->getSolitaryResource();
|
||||
if (surf)
|
||||
g_pHyprRenderer->setSurfaceScanoutMode(surf, EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->m_self.lock() : nullptr);
|
||||
}
|
||||
|
||||
g_pConfigManager->ensureVRR(PMONITOR);
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "HyprCtl.hpp"
|
||||
#include "helpers/Monitor.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
@@ -109,6 +110,91 @@ static std::string availableModesForOutput(PHLMONITOR pMonitor, eHyprCtlOutputFo
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::array<const char*, CMonitor::SC_CHECKS_COUNT> SOLITARY_REASONS_JSON = {
|
||||
"\"UNKNOWN\"", "\"NOTIFICATION\"", "\"LOCK\"", "\"WORKSPACE\"", "\"WINDOWED\"", "\"DND\"", "\"SPECIAL\"", "\"ALPHA\"",
|
||||
"\"OFFSET\"", "\"CANDIDATE\"", "\"OPAQUE\"", "\"TRANSFORM\"", "\"OVERLAYS\"", "\"FLOAT\"", "\"WORKSPACES\"", "\"SURFACES\"",
|
||||
};
|
||||
|
||||
const std::array<const char*, CMonitor::SC_CHECKS_COUNT> SOLITARY_REASONS_TEXT = {
|
||||
"unknown reason", "notification", "session lock", "invalid workspace", "windowed mode", "dnd active", "special workspace", "alpha channel",
|
||||
"workspace offset", "missing candidate", "not opaque", "surface transformations", "other overlays", "floating windows", "other workspaces", "subsurfaces",
|
||||
};
|
||||
|
||||
std::string CHyprCtl::getSolitaryBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
|
||||
const auto reasons = m->isSolitaryBlocked(true);
|
||||
if (!reasons)
|
||||
return "null";
|
||||
|
||||
std::string reasonStr = "";
|
||||
const auto TEXTS = format == eHyprCtlOutputFormat::FORMAT_JSON ? SOLITARY_REASONS_JSON : SOLITARY_REASONS_TEXT;
|
||||
|
||||
for (int i = 0; i < CMonitor::SC_CHECKS_COUNT; i++) {
|
||||
if (reasons & (1 << i)) {
|
||||
if (reasonStr != "")
|
||||
reasonStr += ",";
|
||||
reasonStr += TEXTS[i];
|
||||
}
|
||||
}
|
||||
|
||||
return format == eHyprCtlOutputFormat::FORMAT_JSON ? "[" + reasonStr + "]" : reasonStr;
|
||||
}
|
||||
|
||||
const std::array<const char*, CMonitor::DS_CHECKS_COUNT> DS_REASONS_JSON = {
|
||||
"\"UNKNOWN\"", "\"USER\"", "\"WINDOWED\"", "\"CONTENT\"", "\"MIRROR\"", "\"RECORD\"", "\"SW\"",
|
||||
"\"CANDIDATE\"", "\"SURFACE\"", "\"TRANSFORM\"", "\"DMA\"", "\"TEARING\"", "\"FAILED\"",
|
||||
};
|
||||
|
||||
const std::array<const char*, CMonitor::DS_CHECKS_COUNT> DS_REASONS_TEXT = {
|
||||
"unknown reason", "user settings", "windowed mode", "content type", "monitor mirrors", "screen record/screenshot", "software renders/cursors",
|
||||
"missing candidate", "invalid surface", "surface transformations", "invalid buffer", "tearing", "activation failed",
|
||||
};
|
||||
|
||||
std::string CHyprCtl::getDSBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
|
||||
const auto reasons = m->isDSBlocked(true);
|
||||
if (!reasons)
|
||||
return "null";
|
||||
|
||||
std::string reasonStr = "";
|
||||
const auto TEXTS = format == eHyprCtlOutputFormat::FORMAT_JSON ? DS_REASONS_JSON : DS_REASONS_TEXT;
|
||||
|
||||
for (int i = 0; i < CMonitor::DS_CHECKS_COUNT; i++) {
|
||||
if (reasons & (1 << i)) {
|
||||
if (reasonStr != "")
|
||||
reasonStr += ",";
|
||||
reasonStr += TEXTS[i];
|
||||
}
|
||||
}
|
||||
|
||||
return format == eHyprCtlOutputFormat::FORMAT_JSON ? "[" + reasonStr + "]" : reasonStr;
|
||||
}
|
||||
|
||||
const std::array<const char*, CMonitor::TC_CHECKS_COUNT> TEARING_REASONS_JSON = {
|
||||
"\"UNKNOWN\"", "\"NOT_TORN\"", "\"USER\"", "\"ZOOM\"", "\"SUPPORT\"", "\"CANDIDATE\"", "\"WINDOW\"",
|
||||
};
|
||||
|
||||
const std::array<const char*, CMonitor::TC_CHECKS_COUNT> TEARING_REASONS_TEXT = {
|
||||
"unknown reason", "next frame is not torn", "user settings", "zoom", "not supported by monitor", "missing candidate", "window settings",
|
||||
};
|
||||
|
||||
std::string CHyprCtl::getTearingBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
|
||||
const auto reasons = m->isTearingBlocked(true);
|
||||
if (!reasons || (reasons == CMonitor::TC_NOT_TORN && m->m_tearingState.activelyTearing))
|
||||
return "null";
|
||||
|
||||
std::string reasonStr = "";
|
||||
const auto TEXTS = format == eHyprCtlOutputFormat::FORMAT_JSON ? TEARING_REASONS_JSON : TEARING_REASONS_TEXT;
|
||||
|
||||
for (int i = 0; i < CMonitor::TC_CHECKS_COUNT; i++) {
|
||||
if (reasons & (1 << i)) {
|
||||
if (reasonStr != "")
|
||||
reasonStr += ",";
|
||||
reasonStr += TEXTS[i];
|
||||
}
|
||||
}
|
||||
|
||||
return format == eHyprCtlOutputFormat::FORMAT_JSON ? "[" + reasonStr + "]" : reasonStr;
|
||||
}
|
||||
|
||||
std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
|
||||
std::string result;
|
||||
if (!m->m_output || m->m_id == -1)
|
||||
@@ -146,8 +232,11 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
|
||||
"dpmsStatus": {},
|
||||
"vrr": {},
|
||||
"solitary": "{:x}",
|
||||
"solitaryBlockedBy": {},
|
||||
"activelyTearing": {},
|
||||
"tearingBlockedBy": {},
|
||||
"directScanoutTo": "{:x}",
|
||||
"directScanoutBlockedBy": {},
|
||||
"disabled": {},
|
||||
"currentFormat": "{}",
|
||||
"mirrorOf": "{}",
|
||||
@@ -155,28 +244,32 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
|
||||
}},)#",
|
||||
|
||||
m->m_id, escapeJSONStrings(m->m_name), escapeJSONStrings(m->m_shortDescription), escapeJSONStrings(m->m_output->make), escapeJSONStrings(m->m_output->model),
|
||||
escapeJSONStrings(m->m_output->serial), sc<int>(m->m_pixelSize.x), m->m_pixelSize.y, sc<int>(m->m_output->physicalSize.x), sc<int>(m->m_output->physicalSize.y),
|
||||
m->m_refreshRate, sc<int>(m->m_position.x), sc<int>(m->m_position.y), m->activeWorkspaceID(),
|
||||
escapeJSONStrings(m->m_output->serial), sc<int>(m->m_pixelSize.x), sc<int>(m->m_pixelSize.y), sc<int>(m->m_output->physicalSize.x),
|
||||
sc<int>(m->m_output->physicalSize.y), m->m_refreshRate, sc<int>(m->m_position.x), sc<int>(m->m_position.y), m->activeWorkspaceID(),
|
||||
(!m->m_activeWorkspace ? "" : escapeJSONStrings(m->m_activeWorkspace->m_name)), m->activeSpecialWorkspaceID(),
|
||||
escapeJSONStrings(m->m_activeSpecialWorkspace ? m->m_activeSpecialWorkspace->m_name : ""), sc<int>(m->m_reservedTopLeft.x), sc<int>(m->m_reservedTopLeft.y),
|
||||
sc<int>(m->m_reservedBottomRight.x), sc<int>(m->m_reservedBottomRight.y), m->m_scale, sc<int>(m->m_transform), (m == g_pCompositor->m_lastMonitor ? "true" : "false"),
|
||||
(m->m_dpmsStatus ? "true" : "false"), (m->m_output->state->state().adaptiveSync ? "true" : "false"), rc<uint64_t>(m->m_solitaryClient.get()),
|
||||
(m->m_tearingState.activelyTearing ? "true" : "false"), rc<uint64_t>(m->m_lastScanout.get()), (m->m_enabled ? "false" : "true"),
|
||||
formatToString(m->m_output->state->state().drmFormat), m->m_mirrorOf ? std::format("{}", m->m_mirrorOf->m_id) : "none", availableModesForOutput(m, format));
|
||||
getSolitaryBlockedReason(m, format), (m->m_tearingState.activelyTearing ? "true" : "false"), getTearingBlockedReason(m, format), rc<uint64_t>(m->m_lastScanout.get()),
|
||||
getDSBlockedReason(m, format), (m->m_enabled ? "false" : "true"), formatToString(m->m_output->state->state().drmFormat),
|
||||
m->m_mirrorOf ? std::format("{}", m->m_mirrorOf->m_id) : "none", availableModesForOutput(m, format));
|
||||
|
||||
} else {
|
||||
result += std::format(
|
||||
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tphysical size (mm): {}x{}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
|
||||
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
|
||||
"dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdirectScanoutTo: {:x}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: "
|
||||
"dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tsolitaryBlockedBy: {}\n\tactivelyTearing: {}\n\ttearingBlockedBy: {}\n\tdirectScanoutTo: "
|
||||
"{:x}\n\tdirectScanoutBlockedBy: {}\n\tdisabled: "
|
||||
"{}\n\tcurrentFormat: {}\n\tmirrorOf: "
|
||||
"{}\n\tavailableModes: {}\n\n",
|
||||
m->m_name, m->m_id, sc<int>(m->m_pixelSize.x), sc<int>(m->m_pixelSize.y), m->m_refreshRate, sc<int>(m->m_position.x), sc<int>(m->m_position.y), m->m_shortDescription,
|
||||
m->m_output->make, m->m_output->model, sc<int>(m->m_output->physicalSize.x), sc<int>(m->m_output->physicalSize.y), m->m_output->serial, m->activeWorkspaceID(),
|
||||
(!m->m_activeWorkspace ? "" : m->m_activeWorkspace->m_name), m->activeSpecialWorkspaceID(), (m->m_activeSpecialWorkspace ? m->m_activeSpecialWorkspace->m_name : ""),
|
||||
sc<int>(m->m_reservedTopLeft.x), sc<int>(m->m_reservedTopLeft.y), sc<int>(m->m_reservedBottomRight.x), sc<int>(m->m_reservedBottomRight.y), m->m_scale,
|
||||
sc<int>(m->m_transform), (m == g_pCompositor->m_lastMonitor ? "yes" : "no"), sc<int>(m->m_dpmsStatus), m->m_output->state->state().adaptiveSync,
|
||||
rc<uint64_t>(m->m_solitaryClient.get()), m->m_tearingState.activelyTearing, rc<uint64_t>(m->m_lastScanout.get()), !m->m_enabled,
|
||||
formatToString(m->m_output->state->state().drmFormat), m->m_mirrorOf ? std::format("{}", m->m_mirrorOf->m_id) : "none", availableModesForOutput(m, format));
|
||||
rc<uint64_t>(m->m_solitaryClient.get()), getSolitaryBlockedReason(m, format), m->m_tearingState.activelyTearing, getTearingBlockedReason(m, format),
|
||||
rc<uint64_t>(m->m_lastScanout.get()), getDSBlockedReason(m, format), !m->m_enabled, formatToString(m->m_output->state->state().drmFormat),
|
||||
m->m_mirrorOf ? std::format("{}", m->m_mirrorOf->m_id) : "none", availableModesForOutput(m, format));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -33,6 +33,9 @@ class CHyprCtl {
|
||||
|
||||
static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format);
|
||||
static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format);
|
||||
static std::string getSolitaryBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format);
|
||||
static std::string getDSBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format);
|
||||
static std::string getTearingBlockedReason(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format);
|
||||
static std::string getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format);
|
||||
|
||||
private:
|
||||
|
@@ -385,6 +385,9 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
|
||||
nodes2.reserve(nodes.size() * 2);
|
||||
|
||||
for (auto const& n : nodes) {
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
for (auto const& c : n->m_children) {
|
||||
nodes2.push_back(c->m_self);
|
||||
}
|
||||
@@ -395,6 +398,9 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
|
||||
}
|
||||
|
||||
void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) {
|
||||
if (!m_self)
|
||||
return;
|
||||
|
||||
std::vector<WP<CPopup>> popups;
|
||||
popups.push_back(m_self);
|
||||
bfHelper(popups, fn, data);
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "../managers/ANRManager.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/core/Subcompositor.hpp"
|
||||
#include "../protocols/ContentType.hpp"
|
||||
#include "../protocols/FractionalScale.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
@@ -1180,7 +1181,8 @@ bool CWindow::opaque() {
|
||||
if (m_isX11 && m_xwaylandSurface && m_xwaylandSurface->m_surface && m_xwaylandSurface->m_surface->m_current.texture)
|
||||
return m_xwaylandSurface->m_surface->m_current.texture->m_opaque;
|
||||
|
||||
if (!m_wlSurface->resource() || !m_wlSurface->resource()->m_current.texture)
|
||||
auto solitaryResource = getSolitaryResource();
|
||||
if (!solitaryResource || !solitaryResource->m_current.texture)
|
||||
return false;
|
||||
|
||||
// TODO: this is wrong
|
||||
@@ -1188,7 +1190,7 @@ bool CWindow::opaque() {
|
||||
if (EXTENTS.w >= m_xdgSurface->m_surface->m_current.bufferSize.x && EXTENTS.h >= m_xdgSurface->m_surface->m_current.bufferSize.y)
|
||||
return true;
|
||||
|
||||
return m_wlSurface->resource()->m_current.texture->m_opaque;
|
||||
return solitaryResource->m_current.texture->m_opaque;
|
||||
}
|
||||
|
||||
float CWindow::rounding() {
|
||||
@@ -1324,7 +1326,7 @@ void CWindow::onFocusAnimUpdate() {
|
||||
}
|
||||
|
||||
int CWindow::popupsCount() {
|
||||
if (m_isX11)
|
||||
if (m_isX11 || !m_popupHead)
|
||||
return 0;
|
||||
|
||||
int no = -1;
|
||||
@@ -1870,3 +1872,29 @@ PHLWINDOW CWindow::parent() {
|
||||
bool CWindow::priorityFocus() {
|
||||
return !m_isX11 && CAsyncDialogBox::isPriorityDialogBox(getPID());
|
||||
}
|
||||
|
||||
SP<CWLSurfaceResource> CWindow::getSolitaryResource() {
|
||||
if (!m_wlSurface || !m_wlSurface->resource())
|
||||
return nullptr;
|
||||
|
||||
auto res = m_wlSurface->resource();
|
||||
if (m_isX11)
|
||||
return res;
|
||||
|
||||
if (popupsCount())
|
||||
return nullptr;
|
||||
|
||||
if (res->m_subsurfaces.size() == 0)
|
||||
return res;
|
||||
|
||||
if (res->m_subsurfaces.size() == 1) {
|
||||
if (res->m_subsurfaces[0].expired() || res->m_subsurfaces[0]->m_surface.expired())
|
||||
return nullptr;
|
||||
auto surf = res->m_subsurfaces[0]->m_surface.lock();
|
||||
if (!surf || surf->m_subsurfaces.size() != 0 || surf->extends() != res->extends() || !surf->m_current.texture || !surf->m_current.texture->m_opaque)
|
||||
return nullptr;
|
||||
return surf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
@@ -413,6 +413,7 @@ class CWindow {
|
||||
std::optional<std::string> xdgDescription();
|
||||
PHLWINDOW parent();
|
||||
bool priorityFocus();
|
||||
SP<CWLSurfaceResource> getSolitaryResource();
|
||||
|
||||
CBox getWindowMainSurfaceBox() const {
|
||||
return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y};
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "../managers/PointerManager.hpp"
|
||||
#include "../managers/eventLoop/EventLoopManager.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/core/DataDevice.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
#include "../managers/EventManager.hpp"
|
||||
#include "../managers/LayoutManager.hpp"
|
||||
@@ -1491,33 +1492,260 @@ void CMonitor::setCTM(const Mat3x3& ctm_) {
|
||||
g_pCompositor->scheduleFrameForMonitor(m_self.lock(), Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME);
|
||||
}
|
||||
|
||||
bool CMonitor::attemptDirectScanout() {
|
||||
if (!m_mirrors.empty() || isMirror() || g_pHyprRenderer->m_directScanoutBlocked)
|
||||
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
|
||||
uint16_t CMonitor::isSolitaryBlocked(bool full) {
|
||||
uint16_t reasons = 0;
|
||||
|
||||
if (g_pPointerManager->softwareLockedFor(m_self.lock()))
|
||||
return false;
|
||||
if (g_pHyprNotificationOverlay->hasAny()) {
|
||||
reasons |= SC_NOTIFICATION;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (g_pSessionLockManager->isSessionLocked()) {
|
||||
reasons |= SC_LOCK;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = m_activeWorkspace;
|
||||
if (!PWORKSPACE) {
|
||||
reasons |= SC_WORKSPACE;
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!PWORKSPACE->m_hasFullscreenWindow) {
|
||||
reasons |= SC_WINDOWED;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (PROTO::data->dndActive()) {
|
||||
reasons |= SC_DND;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (m_activeSpecialWorkspace) {
|
||||
reasons |= SC_SPECIAL;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_alpha->value() != 1.f) {
|
||||
reasons |= SC_ALPHA;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_renderOffset->value() != Vector2D{}) {
|
||||
reasons |= SC_OFFSET;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
const auto PCANDIDATE = PWORKSPACE->getFullscreenWindow();
|
||||
|
||||
if (!PCANDIDATE) {
|
||||
reasons |= SC_CANDIDATE;
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!PCANDIDATE->opaque()) {
|
||||
reasons |= SC_OPAQUE;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (PCANDIDATE->m_realSize->value() != m_size || PCANDIDATE->m_realPosition->value() != m_position || PCANDIDATE->m_realPosition->isBeingAnimated() ||
|
||||
PCANDIDATE->m_realSize->isBeingAnimated()) {
|
||||
reasons |= SC_TRANSFORM;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty()) {
|
||||
reasons |= SC_OVERLAYS;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
for (auto const& topls : m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (topls->m_alpha->value() != 0.f) {
|
||||
reasons |= SC_OVERLAYS;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& w : g_pCompositor->m_windows) {
|
||||
if (w == PCANDIDATE || (!w->m_isMapped && !w->m_fadingOut) || w->isHidden())
|
||||
continue;
|
||||
|
||||
if (w->workspaceID() == PCANDIDATE->workspaceID() && w->m_isFloating && w->m_createdOverFullscreen && w->visibleOnMonitor(m_self.lock())) {
|
||||
reasons |= SC_FLOAT;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& ws : g_pCompositor->getWorkspaces()) {
|
||||
if (ws->m_alpha->value() <= 0.F || !ws->m_isSpecialWorkspace || ws->m_monitor != m_self)
|
||||
continue;
|
||||
|
||||
reasons |= SC_WORKSPACES;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
// check if it did not open any subsurfaces or shit
|
||||
if (!PCANDIDATE->getSolitaryResource())
|
||||
reasons |= SC_SURFACES;
|
||||
|
||||
return reasons;
|
||||
}
|
||||
|
||||
void CMonitor::recheckSolitary() {
|
||||
m_solitaryClient.reset(); // reset it, if we find one it will be set.
|
||||
if (isSolitaryBlocked())
|
||||
return;
|
||||
|
||||
m_solitaryClient = m_activeWorkspace->getFullscreenWindow();
|
||||
}
|
||||
|
||||
uint8_t CMonitor::isTearingBlocked(bool full) {
|
||||
uint8_t reasons = 0;
|
||||
|
||||
static auto PTEARINGENABLED = CConfigValue<Hyprlang::INT>("general:allow_tearing");
|
||||
|
||||
if (!m_tearingState.nextRenderTorn) {
|
||||
reasons |= TC_NOT_TORN;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!*PTEARINGENABLED) {
|
||||
Debug::log(WARN, "Tearing commit requested but the master switch general:allow_tearing is off, ignoring");
|
||||
reasons |= TC_USER;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (g_pHyprOpenGL->m_renderData.mouseZoomFactor != 1.0) {
|
||||
Debug::log(WARN, "Tearing commit requested but scale factor is not 1, ignoring");
|
||||
reasons |= TC_ZOOM;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!m_tearingState.canTear) {
|
||||
Debug::log(WARN, "Tearing commit requested but monitor doesn't support it, ignoring");
|
||||
reasons |= TC_SUPPORT;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (m_solitaryClient.expired()) {
|
||||
reasons |= TC_CANDIDATE;
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!m_solitaryClient->canBeTorn())
|
||||
reasons |= TC_WINDOW;
|
||||
|
||||
return reasons;
|
||||
}
|
||||
|
||||
bool CMonitor::updateTearing() {
|
||||
m_tearingState.activelyTearing = !isTearingBlocked();
|
||||
m_tearingState.nextRenderTorn = false;
|
||||
return m_tearingState.activelyTearing;
|
||||
}
|
||||
|
||||
uint16_t CMonitor::isDSBlocked(bool full) {
|
||||
uint16_t reasons = 0;
|
||||
static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
|
||||
|
||||
if (*PDIRECTSCANOUT == 0) {
|
||||
reasons |= DS_BLOCK_USER;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (*PDIRECTSCANOUT == 2) {
|
||||
if (!m_activeWorkspace || !m_activeWorkspace->m_hasFullscreenWindow || m_activeWorkspace->m_fullscreenMode != FSMODE_FULLSCREEN) {
|
||||
reasons |= DS_BLOCK_WINDOWED;
|
||||
if (!full)
|
||||
return reasons;
|
||||
} else if (m_activeWorkspace->getFullscreenWindow()->getContentType() != CONTENT_TYPE_GAME) {
|
||||
reasons |= DS_BLOCK_CONTENT;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_tearingState.activelyTearing) {
|
||||
reasons |= DS_BLOCK_TEARING;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!m_mirrors.empty() || isMirror()) {
|
||||
reasons |= DS_BLOCK_MIRROR;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (g_pHyprRenderer->m_directScanoutBlocked) {
|
||||
reasons |= DS_BLOCK_RECORD;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (g_pPointerManager->softwareLockedFor(m_self.lock())) {
|
||||
reasons |= DS_BLOCK_SW;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
const auto PCANDIDATE = m_solitaryClient.lock();
|
||||
if (!PCANDIDATE) {
|
||||
reasons |= DS_BLOCK_CANDIDATE;
|
||||
return reasons;
|
||||
}
|
||||
|
||||
if (!PCANDIDATE)
|
||||
return false;
|
||||
const auto PSURFACE = PCANDIDATE->getSolitaryResource();
|
||||
if (!PSURFACE || !PSURFACE->m_current.texture || !PSURFACE->m_current.buffer) {
|
||||
reasons |= DS_BLOCK_SURFACE;
|
||||
return reasons;
|
||||
}
|
||||
|
||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
||||
|
||||
if (!PSURFACE || !PSURFACE->m_current.texture || !PSURFACE->m_current.buffer)
|
||||
return false;
|
||||
|
||||
if (PSURFACE->m_current.bufferSize != m_pixelSize || PSURFACE->m_current.transform != m_transform)
|
||||
return false;
|
||||
if (PSURFACE->m_current.bufferSize != m_pixelSize || PSURFACE->m_current.transform != m_transform) {
|
||||
reasons |= DS_BLOCK_TRANSFORM;
|
||||
if (!full)
|
||||
return reasons;
|
||||
}
|
||||
|
||||
// we can't scanout shm buffers.
|
||||
const auto params = PSURFACE->m_current.buffer->dmabuf();
|
||||
if (!params.success || !PSURFACE->m_current.texture->m_eglImage /* dmabuf */)
|
||||
return false;
|
||||
reasons |= DS_BLOCK_DMA;
|
||||
|
||||
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {}", rc<uintptr_t>(PSURFACE.get()),
|
||||
rc<uintptr_t>(PSURFACE->m_current.buffer.m_buffer.get()));
|
||||
return reasons;
|
||||
}
|
||||
|
||||
bool CMonitor::attemptDirectScanout() {
|
||||
const auto blockedReason = isDSBlocked();
|
||||
if (blockedReason) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: blocked by {}", blockedReason);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto PCANDIDATE = m_solitaryClient.lock();
|
||||
const auto PSURFACE = PCANDIDATE->getSolitaryResource();
|
||||
const auto params = PSURFACE->m_current.buffer->dmabuf();
|
||||
|
||||
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {} fmt: {} -> {} (mod {})", rc<uintptr_t>(PSURFACE.get()),
|
||||
rc<uintptr_t>(PSURFACE->m_current.buffer.m_buffer.get()), m_drmFormat, params.format, params.modifier);
|
||||
|
||||
auto PBUFFER = PSURFACE->m_current.buffer.m_buffer;
|
||||
|
||||
@@ -1526,7 +1754,7 @@ bool CMonitor::attemptDirectScanout() {
|
||||
|
||||
if (m_scanoutNeedsCursorUpdate) {
|
||||
if (!m_state.test()) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed basic test");
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed basic test on cursor update");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1555,6 +1783,7 @@ bool CMonitor::attemptDirectScanout() {
|
||||
}
|
||||
|
||||
m_output->state->setBuffer(PBUFFER);
|
||||
Debug::log(TRACE, "attemptDirectScanout: setting presentation mode");
|
||||
m_output->state->setPresentationMode(m_tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
|
||||
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
|
||||
|
||||
|
@@ -212,6 +212,66 @@ class CMonitor {
|
||||
|
||||
std::array<std::vector<PHLLSREF>, 4> m_layerSurfaceLayers;
|
||||
|
||||
// keep in sync with HyprCtl
|
||||
enum eDSBlockReason : uint16_t {
|
||||
DS_OK = 0,
|
||||
|
||||
DS_BLOCK_UNKNOWN = (1 << 0),
|
||||
DS_BLOCK_USER = (1 << 1),
|
||||
DS_BLOCK_WINDOWED = (1 << 2),
|
||||
DS_BLOCK_CONTENT = (1 << 3),
|
||||
DS_BLOCK_MIRROR = (1 << 4),
|
||||
DS_BLOCK_RECORD = (1 << 5),
|
||||
DS_BLOCK_SW = (1 << 6),
|
||||
DS_BLOCK_CANDIDATE = (1 << 7),
|
||||
DS_BLOCK_SURFACE = (1 << 8),
|
||||
DS_BLOCK_TRANSFORM = (1 << 9),
|
||||
DS_BLOCK_DMA = (1 << 10),
|
||||
DS_BLOCK_TEARING = (1 << 11),
|
||||
DS_BLOCK_FAILED = (1 << 12),
|
||||
|
||||
DS_CHECKS_COUNT = 13,
|
||||
};
|
||||
|
||||
// keep in sync with HyprCtl
|
||||
enum eSolitaryCheck : uint16_t {
|
||||
SC_OK = 0,
|
||||
|
||||
SC_UNKNOWN = (1 << 0),
|
||||
SC_NOTIFICATION = (1 << 1),
|
||||
SC_LOCK = (1 << 2),
|
||||
SC_WORKSPACE = (1 << 3),
|
||||
SC_WINDOWED = (1 << 4),
|
||||
SC_DND = (1 << 5),
|
||||
SC_SPECIAL = (1 << 6),
|
||||
SC_ALPHA = (1 << 7),
|
||||
SC_OFFSET = (1 << 8),
|
||||
SC_CANDIDATE = (1 << 9),
|
||||
SC_OPAQUE = (1 << 10),
|
||||
SC_TRANSFORM = (1 << 11),
|
||||
SC_OVERLAYS = (1 << 12),
|
||||
SC_FLOAT = (1 << 13),
|
||||
SC_WORKSPACES = (1 << 14),
|
||||
SC_SURFACES = (1 << 15),
|
||||
|
||||
SC_CHECKS_COUNT = 16,
|
||||
};
|
||||
|
||||
// keep in sync with HyprCtl
|
||||
enum eTearingCheck : uint8_t {
|
||||
TC_OK = 0,
|
||||
|
||||
TC_UNKNOWN = (1 << 0),
|
||||
TC_NOT_TORN = (1 << 1),
|
||||
TC_USER = (1 << 2),
|
||||
TC_ZOOM = (1 << 3),
|
||||
TC_SUPPORT = (1 << 4),
|
||||
TC_CANDIDATE = (1 << 5),
|
||||
TC_WINDOW = (1 << 6),
|
||||
|
||||
TC_CHECKS_COUNT = 7,
|
||||
};
|
||||
|
||||
// methods
|
||||
void onConnect(bool noRule);
|
||||
void onDisconnect(bool destroy = false);
|
||||
@@ -236,6 +296,11 @@ class CMonitor {
|
||||
WORKSPACEID activeSpecialWorkspaceID();
|
||||
CBox logicalBox();
|
||||
void scheduleDone();
|
||||
uint16_t isSolitaryBlocked(bool full = false);
|
||||
void recheckSolitary();
|
||||
uint8_t isTearingBlocked(bool full = false);
|
||||
bool updateTearing();
|
||||
uint16_t isDSBlocked(bool full = false);
|
||||
bool attemptDirectScanout();
|
||||
void setCTM(const Mat3x3& ctm);
|
||||
void onCursorMovedOnMonitor();
|
||||
|
@@ -80,7 +80,7 @@ void CMonitorFrameScheduler::onFrame() {
|
||||
if (!canRender())
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->recheckSolitaryForMonitor(m_monitor.lock());
|
||||
m_monitor->recheckSolitary();
|
||||
|
||||
m_monitor->m_tearingState.busy = false;
|
||||
|
||||
|
@@ -1188,9 +1188,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
|
||||
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
|
||||
static auto PDAMAGETRACKINGMODE = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
||||
static auto PDAMAGEBLINK = CConfigValue<Hyprlang::INT>("debug:damage_blink");
|
||||
static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
|
||||
static auto PVFR = CConfigValue<Hyprlang::INT>("misc:vfr");
|
||||
static auto PTEARINGENABLED = CConfigValue<Hyprlang::INT>("general:allow_tearing");
|
||||
|
||||
static int damageBlinkCleanup = 0; // because double-buffered
|
||||
|
||||
@@ -1230,47 +1228,19 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
|
||||
return;
|
||||
|
||||
// tearing and DS first
|
||||
bool shouldTear = false;
|
||||
if (pMonitor->m_tearingState.nextRenderTorn) {
|
||||
pMonitor->m_tearingState.nextRenderTorn = false;
|
||||
bool shouldTear = pMonitor->updateTearing();
|
||||
|
||||
if (!*PTEARINGENABLED) {
|
||||
Debug::log(WARN, "Tearing commit requested but the master switch general:allow_tearing is off, ignoring");
|
||||
return;
|
||||
}
|
||||
if (pMonitor->attemptDirectScanout()) {
|
||||
return;
|
||||
} else if (!pMonitor->m_lastScanout.expired()) {
|
||||
Debug::log(LOG, "Left a direct scanout.");
|
||||
pMonitor->m_lastScanout.reset();
|
||||
|
||||
if (g_pHyprOpenGL->m_renderData.mouseZoomFactor != 1.0) {
|
||||
Debug::log(WARN, "Tearing commit requested but scale factor is not 1, ignoring");
|
||||
return;
|
||||
}
|
||||
// reset DRM format, but only if needed since it might modeset
|
||||
if (pMonitor->m_output->state->state().drmFormat != pMonitor->m_prevDrmFormat)
|
||||
pMonitor->m_output->state->setFormat(pMonitor->m_prevDrmFormat);
|
||||
|
||||
if (!pMonitor->m_tearingState.canTear) {
|
||||
Debug::log(WARN, "Tearing commit requested but monitor doesn't support it, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pMonitor->m_solitaryClient.expired())
|
||||
shouldTear = true;
|
||||
}
|
||||
|
||||
pMonitor->m_tearingState.activelyTearing = shouldTear;
|
||||
|
||||
if ((*PDIRECTSCANOUT == 1 ||
|
||||
(*PDIRECTSCANOUT == 2 && pMonitor->m_activeWorkspace && pMonitor->m_activeWorkspace->m_hasFullscreenWindow &&
|
||||
pMonitor->m_activeWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN && pMonitor->m_activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) &&
|
||||
!shouldTear) {
|
||||
if (pMonitor->attemptDirectScanout()) {
|
||||
return;
|
||||
} else if (!pMonitor->m_lastScanout.expired()) {
|
||||
Debug::log(LOG, "Left a direct scanout.");
|
||||
pMonitor->m_lastScanout.reset();
|
||||
|
||||
// reset DRM format, but only if needed since it might modeset
|
||||
if (pMonitor->m_output->state->state().drmFormat != pMonitor->m_prevDrmFormat)
|
||||
pMonitor->m_output->state->setFormat(pMonitor->m_prevDrmFormat);
|
||||
|
||||
pMonitor->m_drmFormat = pMonitor->m_prevDrmFormat;
|
||||
}
|
||||
pMonitor->m_drmFormat = pMonitor->m_prevDrmFormat;
|
||||
}
|
||||
|
||||
EMIT_HOOK_EVENT("preRender", pMonitor);
|
||||
@@ -2143,70 +2113,6 @@ void CHyprRenderer::initiateManualCrash() {
|
||||
**PDT = 0;
|
||||
}
|
||||
|
||||
void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) {
|
||||
pMonitor->m_solitaryClient.reset(); // reset it, if we find one it will be set.
|
||||
|
||||
if (g_pHyprNotificationOverlay->hasAny() || g_pSessionLockManager->isSessionLocked())
|
||||
return;
|
||||
|
||||
const auto PWORKSPACE = pMonitor->m_activeWorkspace;
|
||||
|
||||
if (!PWORKSPACE || !PWORKSPACE->m_hasFullscreenWindow || PROTO::data->dndActive() || pMonitor->m_activeSpecialWorkspace || PWORKSPACE->m_alpha->value() != 1.f ||
|
||||
PWORKSPACE->m_renderOffset->value() != Vector2D{})
|
||||
return;
|
||||
|
||||
const auto PCANDIDATE = PWORKSPACE->getFullscreenWindow();
|
||||
|
||||
if (!PCANDIDATE)
|
||||
return; // ????
|
||||
|
||||
if (!PCANDIDATE->opaque())
|
||||
return;
|
||||
|
||||
if (PCANDIDATE->m_realSize->value() != pMonitor->m_size || PCANDIDATE->m_realPosition->value() != pMonitor->m_position || PCANDIDATE->m_realPosition->isBeingAnimated() ||
|
||||
PCANDIDATE->m_realSize->isBeingAnimated())
|
||||
return;
|
||||
|
||||
if (!pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty())
|
||||
return;
|
||||
|
||||
for (auto const& topls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (topls->m_alpha->value() != 0.f)
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto const& w : g_pCompositor->m_windows) {
|
||||
if (w == PCANDIDATE || (!w->m_isMapped && !w->m_fadingOut) || w->isHidden())
|
||||
continue;
|
||||
|
||||
if (w->workspaceID() == PCANDIDATE->workspaceID() && w->m_isFloating && w->m_createdOverFullscreen && w->visibleOnMonitor(pMonitor))
|
||||
return;
|
||||
}
|
||||
|
||||
if (pMonitor->m_activeSpecialWorkspace)
|
||||
return;
|
||||
|
||||
for (auto const& ws : g_pCompositor->getWorkspaces()) {
|
||||
if (ws->m_alpha->value() <= 0.F || !ws->m_isSpecialWorkspace || ws->m_monitor != pMonitor)
|
||||
continue;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if it did not open any subsurfaces or shit
|
||||
int surfaceCount = 0;
|
||||
if (PCANDIDATE->m_isX11)
|
||||
surfaceCount = 1;
|
||||
else
|
||||
surfaceCount = PCANDIDATE->popupsCount() + PCANDIDATE->surfacesCount();
|
||||
|
||||
if (surfaceCount > 1)
|
||||
return;
|
||||
|
||||
// found one!
|
||||
pMonitor->m_solitaryClient = PCANDIDATE;
|
||||
}
|
||||
|
||||
SP<CRenderbuffer> CHyprRenderer::getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
|
||||
auto it = std::ranges::find_if(m_renderbuffers, [&](const auto& other) { return other->m_hlBuffer == buffer; });
|
||||
|
||||
|
@@ -69,7 +69,6 @@ class CHyprRenderer {
|
||||
bool fixMisalignedFSV1 = false);
|
||||
std::tuple<float, float, float> getRenderTimes(PHLMONITOR pMonitor); // avg max min
|
||||
void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
|
||||
void recheckSolitaryForMonitor(PHLMONITOR pMonitor);
|
||||
void setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
|
||||
void setCursorFromName(const std::string& name, bool force = false);
|
||||
void onRenderbufferDestroy(CRenderbuffer* rb);
|
||||
|
Reference in New Issue
Block a user