From c757fd375cce299e3da922190ddf1a0622ce807c Mon Sep 17 00:00:00 2001 From: Alvaro Parker <64918109+AlvaroParker@users.noreply.github.com> Date: Wed, 5 Nov 2025 21:06:31 -0300 Subject: compositor: block parent window interaction when modal dialog children window is open (#12057) --- src/Compositor.cpp | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'src/Compositor.cpp') diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3c7ad6a2..3d0b5173 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -881,13 +881,18 @@ bool CCompositor::monitorExists(PHLMONITOR pMonitor) { } PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, PHLWINDOW pIgnoreWindow) { - const auto PMONITOR = getMonitorFromVector(pos); - static auto PRESIZEONBORDER = CConfigValue("general:resize_on_border"); - static auto PBORDERSIZE = CConfigValue("general:border_size"); - static auto PBORDERGRABEXTEND = CConfigValue("general:extend_border_grab_area"); - static auto PSPECIALFALLTHRU = CConfigValue("input:special_fallthrough"); - const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0; - const bool ONLY_PRIORITY = properties & FOCUS_PRIORITY; + const auto PMONITOR = getMonitorFromVector(pos); + static auto PRESIZEONBORDER = CConfigValue("general:resize_on_border"); + static auto PBORDERSIZE = CConfigValue("general:border_size"); + static auto PBORDERGRABEXTEND = CConfigValue("general:extend_border_grab_area"); + static auto PSPECIALFALLTHRU = CConfigValue("input:special_fallthrough"); + static auto PMODALPARENTBLOCKING = CConfigValue("general:modal_parent_blocking"); + const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0; + const bool ONLY_PRIORITY = properties & FOCUS_PRIORITY; + + const auto isShadowedByModal = [](PHLWINDOW w) -> bool { + return *PMODALPARENTBLOCKING && w->m_xdgSurface && w->m_xdgSurface->m_toplevel && w->m_xdgSurface->m_toplevel->anyChildModal(); + }; // pinned windows on top of floating regardless if (properties & ALLOW_FLOATING) { @@ -895,7 +900,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (ONLY_PRIORITY && !w->priorityFocus()) continue; - if (w->m_isFloating && w->m_isMapped && !w->isHidden() && !w->m_X11ShouldntFocus && w->m_pinned && !w->m_windowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { + if (w->m_isFloating && w->m_isMapped && !w->isHidden() && !w->m_X11ShouldntFocus && w->m_pinned && !w->m_windowData.noFocus.valueOrDefault() && w != pIgnoreWindow && + !isShadowedByModal(w)) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (box.containsPoint(g_pPointerManager->position())) @@ -933,7 +939,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper } if (w->m_isFloating && w->m_isMapped && w->m_workspace->isVisible() && !w->isHidden() && !w->m_pinned && !w->m_windowData.noFocus.valueOrDefault() && - w != pIgnoreWindow && (!aboveFullscreen || w->m_createdOverFullscreen)) { + w != pIgnoreWindow && (!aboveFullscreen || w->m_createdOverFullscreen) && !isShadowedByModal(w)) { // OR windows should add focus to parent if (w->m_X11ShouldntFocus && !w->isX11OverrideRedirect()) continue; @@ -993,7 +999,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; if (!w->m_isX11 && !w->m_isFloating && w->m_isMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_X11ShouldntFocus && - !w->m_windowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { + !w->m_windowData.noFocus.valueOrDefault() && w != pIgnoreWindow && !isShadowedByModal(w)) { if (w->hasPopupAt(pos)) return w; } @@ -1010,7 +1016,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; if (!w->m_isFloating && w->m_isMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_X11ShouldntFocus && !w->m_windowData.noFocus.valueOrDefault() && - w != pIgnoreWindow) { + w != pIgnoreWindow && !isShadowedByModal(w)) { CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_position, w->m_size}; if (box.containsPoint(pos)) return w; @@ -1110,8 +1116,14 @@ PHLMONITOR CCompositor::getRealMonitorFromOutput(SP out) { void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface, bool preserveFocusHistory) { - static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); - static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); + static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); + static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); + static auto PMODALPARENTBLOCKING = CConfigValue("general:modal_parent_blocking"); + + if (*PMODALPARENTBLOCKING && pWindow && pWindow->m_xdgSurface && pWindow->m_xdgSurface->m_toplevel && pWindow->m_xdgSurface->m_toplevel->anyChildModal()) { + Debug::log(LOG, "Refusing focus to window shadowed by modal dialog"); + return; + } if (!pWindow || !pWindow->priorityFocus()) { if (g_pSessionLockManager->isSessionLocked()) { -- cgit v1.2.3