diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5ea88b115..78b19c717 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2842,6 +2842,38 @@ PHLWINDOW CCompositor::getForceFocus() { return nullptr; } +void CCompositor::scheduleMonitorStateRecheck() { + static bool scheduled = false; + + if (!scheduled) { + scheduled = true; + g_pEventLoopManager->doLater([this] { + arrangeMonitors(); + checkMonitorOverlaps(); + + scheduled = false; + }); + } +} + +void CCompositor::checkMonitorOverlaps() { + CRegion monitorRegion; + + for (const auto& m : m_monitors) { + if (!monitorRegion.copy().intersect(m->logicalBox()).empty()) { + Debug::log(ERR, "Monitor {}: detected overlap with layout", m->m_name); + g_pHyprNotificationOverlay->addNotification(std::format("Your monitor layout is set up incorrectly. Monitor {} overlaps with other monitor(s) in the " + "layout.\nPlease see the wiki (Monitors page) for more. This will cause issues.", + m->m_name), + CHyprColor{}, 15000, ICON_WARNING); + + break; + } + + monitorRegion.add(m->logicalBox()); + } +} + void CCompositor::arrangeMonitors() { static auto* const PXWLFORCESCALEZERO = rc(g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index b3e048b27..49222d05d 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -156,7 +156,9 @@ class CCompositor { void performUserChecks(); void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); PHLWINDOW getForceFocus(); + void scheduleMonitorStateRecheck(); void arrangeMonitors(); + void checkMonitorOverlaps(); void enterUnsafeState(); void leaveUnsafeState(); void setPreferredScaleForSurface(SP pSurface, double scale); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 1ec035fd8..ac9c065f0 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -344,7 +344,7 @@ void CMonitor::onDisconnect(bool destroy) { g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", m_name}); g_pEventManager->postEvent(SHyprIPCEvent{"monitorremovedv2", std::format("{},{},{}", m_id, m_name, m_shortDescription)}); EMIT_HOOK_EVENT("monitorRemoved", m_self.lock()); - g_pCompositor->arrangeMonitors(); + g_pCompositor->scheduleMonitorStateRecheck(); }}; m_frameScheduler.reset(); @@ -955,7 +955,7 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { if (WAS10B != m_enabled10bit || OLDRES != m_pixelSize) g_pHyprOpenGL->destroyMonitorResources(m_self); - g_pCompositor->arrangeMonitors(); + g_pCompositor->scheduleMonitorStateRecheck(); m_damage.setSize(m_transformedSize); @@ -1181,7 +1181,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // remove from mvmonitors std::erase_if(g_pCompositor->m_monitors, [&](const auto& other) { return other == m_self; }); - g_pCompositor->arrangeMonitors(); + g_pCompositor->scheduleMonitorStateRecheck(); g_pCompositor->setActiveMonitor(g_pCompositor->m_monitors.front());