From 153df31d2c9f2d366f4aa035db4946cbac2b3729 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:57:46 +0200 Subject: [PATCH] errorOverlay: fix reserved area tracking (#15839) --- hyprtester/src/tests/main/focus.cpp | 55 +++++++++++++++++++++++++++++ src/errorOverlay/Overlay.cpp | 17 +++++---- src/errorOverlay/Overlay.hpp | 2 +- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/hyprtester/src/tests/main/focus.cpp b/hyprtester/src/tests/main/focus.cpp index a228b4de7..39dc30176 100644 --- a/hyprtester/src/tests/main/focus.cpp +++ b/hyprtester/src/tests/main/focus.cpp @@ -6,6 +6,9 @@ #include #include "../shared.hpp" +#include +#include + using namespace Hyprutils::OS; using namespace Hyprutils::Memory; using namespace Hyprutils::Utils; @@ -13,6 +16,58 @@ using namespace Hyprutils::Utils; #define UP CUniquePointer #define SP CSharedPointer +static bool waitForMonitorReservations(const std::string& reservedMonitor, const std::string& clearMonitor) { + for (size_t i = 0; i < 50; ++i) { + const auto result = getFromSocket(std::format("r/repl hl.get_monitor('{}').reserved.top > 0 and hl.get_monitor('{}').reserved.top == 0", reservedMonitor, clearMonitor)); + if (result == "true") + return true; + + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + Tests::sync(); + } + + return false; +} + +static bool waitForMonitorReservationsCleared(const std::string& monitorA, const std::string& monitorB) { + for (size_t i = 0; i < 50; ++i) { + const auto result = getFromSocket(std::format("r/repl hl.get_monitor('{}').reserved.top == 0 and hl.get_monitor('{}').reserved.top == 0", monitorA, monitorB)); + if (result == "true") + return true; + + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + Tests::sync(); + } + + return false; +} + +TEST_CASE(errorBarReservationFollowsFocusedMonitor) { + static constexpr const char* TEST_OUTPUT = "HYPRTEST-ERROR-BAR"; + + getFromSocket(std::format("/output remove {}", TEST_OUTPUT)); + OK(getFromSocket("/eval hl.monitor({ output = 'HEADLESS-2', mode = '1920x1080@60', position = '0x0', scale = '1' })")); + OK(getFromSocket(std::format("/eval hl.monitor({{ output = '{}', mode = '1920x1080@60', position = '1920x0', scale = '1' }})", TEST_OUTPUT))); + OK(getFromSocket(std::format("/output create headless {}", TEST_OUTPUT))); + + CScopeGuard guard = {[&]() { + getFromSocket("/seterror disable"); + getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"); + waitForMonitorReservationsCleared("HEADLESS-2", TEST_OUTPUT); + getFromSocket(std::format("/output remove {}", TEST_OUTPUT)); + }}; + + OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })")); + OK(getFromSocket("/seterror rgb(ff0000) reservation-test")); + ASSERT(waitForMonitorReservations("HEADLESS-2", TEST_OUTPUT), true); + + OK(getFromSocket(std::format("/dispatch hl.dsp.focus({{ monitor = '{}' }})", TEST_OUTPUT))); + ASSERT(waitForMonitorReservations(TEST_OUTPUT, "HEADLESS-2"), true); + + OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })")); + EXPECT(waitForMonitorReservations("HEADLESS-2", TEST_OUTPUT), true); +} + TEST_CASE(crossMonitorFullscreenFocus) { // Create a destination monitor to the right of the default one and pin the // destination workspace to it diff --git a/src/errorOverlay/Overlay.cpp b/src/errorOverlay/Overlay.cpp index cc7b22ad1..4aba7d93f 100644 --- a/src/errorOverlay/Overlay.cpp +++ b/src/errorOverlay/Overlay.cpp @@ -64,7 +64,7 @@ COverlay::COverlay() { return; g_pHyprRenderer->damageMonitor(Desktop::focusState()->monitor()); - updateReservedArea(true); + updateReservedArea(mon); m_monitorChanged = true; }); @@ -154,22 +154,21 @@ void COverlay::createQueued() { g_pHyprRenderer->damageMonitor(PMONITOR); - updateReservedArea(true); + updateReservedArea(PMONITOR); } -void COverlay::updateReservedArea(bool reserve) { +void COverlay::updateReservedArea(PHLMONITOR monitor) { static auto BAR_POSITION = CConfigValue("debug:error_position"); - const auto PMONITOR = Desktop::focusState()->monitor(); - const bool TOPBAR = *BAR_POSITION == 0; + const bool TOPBAR = *BAR_POSITION == 0; for (const auto& m : State::monitorState()->monitors()) { m->m_reservedArea.resetType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR); } - if (reserve && PMONITOR) { - const auto RESERVED = (m_lastHeight + m_outerPad) / PMONITOR->m_scale; - PMONITOR->m_reservedArea.addType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR, Vector2D{0.0, TOPBAR ? RESERVED : 0.0}, Vector2D{0.0, !TOPBAR ? RESERVED : 0.0}); + if (monitor) { + const auto RESERVED = (m_lastHeight + m_outerPad) / monitor->m_scale; + monitor->m_reservedArea.addType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR, Vector2D{0.0, TOPBAR ? RESERVED : 0.0}, Vector2D{0.0, !TOPBAR ? RESERVED : 0.0}); } for (const auto& m : State::monitorState()->monitors()) { @@ -195,7 +194,7 @@ void COverlay::draw() { m_isCreated = false; m_queued = ""; - updateReservedArea(false); + updateReservedArea(nullptr); return; } else { diff --git a/src/errorOverlay/Overlay.hpp b/src/errorOverlay/Overlay.hpp index 0bfbc3aba..8d0cf22b2 100644 --- a/src/errorOverlay/Overlay.hpp +++ b/src/errorOverlay/Overlay.hpp @@ -32,7 +32,7 @@ namespace ErrorOverlay { private: void createQueued(); - void updateReservedArea(bool reserve); + void updateReservedArea(PHLMONITOR monitor); std::string m_queued = ""; Config::CGradientValueData m_queuedBorderGradient; Config::CGradientValueData m_borderGradient;