diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 973cb26b4..c65939235 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -870,10 +870,14 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper 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; // pinned windows on top of floating regardless if (properties & ALLOW_FLOATING) { for (auto const& w : m_windows | std::views::reverse) { + 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) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); @@ -898,6 +902,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (!w->m_workspace) continue; + if (ONLY_PRIORITY && !w->priorityFocus()) + continue; + const auto PWINDOWMONITOR = w->m_monitor.lock(); // to avoid focusing windows behind special workspaces from other monitors @@ -950,7 +957,7 @@ 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 & SKIP_FULLSCREEN_PRIORITY)) + if (PWORKSPACE->m_hasFullscreenWindow && !(properties & SKIP_FULLSCREEN_PRIORITY) && !ONLY_PRIORITY) return PWORKSPACE->getFullscreenWindow(); auto found = floating(false); @@ -959,6 +966,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper // for windows, we need to check their extensions too, first. for (auto const& w : m_windows) { + if (ONLY_PRIORITY && !w->priorityFocus()) + continue; + if (special != w->onSpecialWorkspace()) continue; @@ -973,6 +983,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper } for (auto const& w : m_windows) { + if (ONLY_PRIORITY && !w->priorityFocus()) + continue; + if (special != w->onSpecialWorkspace()) continue; @@ -1083,14 +1096,16 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); - if (g_pSessionLockManager->isSessionLocked()) { - Debug::log(LOG, "Refusing a keyboard focus to a window because of a sessionlock"); - return; - } + if (!pWindow || !pWindow->priorityFocus()) { + if (g_pSessionLockManager->isSessionLocked()) { + Debug::log(LOG, "Refusing a keyboard focus to a window because of a sessionlock"); + return; + } - if (!g_pInputManager->m_exclusiveLSes.empty()) { - Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls"); - return; + if (!g_pInputManager->m_exclusiveLSes.empty()) { + Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls"); + return; + } } if (pWindow && pWindow->m_isX11 && pWindow->isX11OverrideRedirect() && !pWindow->m_xwaylandSurface->wantsFocus()) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7ef54da0e..9f69e364b 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1836,3 +1836,7 @@ PHLWINDOW CWindow::parent() { return m_xdgSurface->m_toplevel->m_parent->m_window.lock(); } + +bool CWindow::priorityFocus() { + return !m_isX11 && CAsyncDialogBox::isPriorityDialogBox(getPID()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 47d28db29..0d06b69cb 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -51,6 +51,7 @@ enum eGetWindowProperties : uint8_t { ALLOW_FLOATING = 1 << 4, USE_PROP_TILED = 1 << 5, SKIP_FULLSCREEN_PRIORITY = 1 << 6, + FOCUS_PRIORITY = 1 << 7, }; enum eSuppressEvents : uint8_t { @@ -408,6 +409,7 @@ class CWindow { std::optional xdgTag(); std::optional xdgDescription(); PHLWINDOW parent(); + bool priorityFocus(); CBox getWindowMainSurfaceBox() const { return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y}; diff --git a/src/helpers/AsyncDialogBox.cpp b/src/helpers/AsyncDialogBox.cpp index 42dac4698..697d61ba8 100644 --- a/src/helpers/AsyncDialogBox.cpp +++ b/src/helpers/AsyncDialogBox.cpp @@ -7,7 +7,7 @@ using namespace Hyprutils::OS; -static std::vector asyncDialogBoxes; +static std::vector>> asyncDialogBoxes; // SP CAsyncDialogBox::create(const std::string& title, const std::string& description, std::vector buttons) { @@ -24,7 +24,18 @@ SP CAsyncDialogBox::create(const std::string& title, const std: } bool CAsyncDialogBox::isAsyncDialogBox(pid_t pid) { - return std::ranges::contains(asyncDialogBoxes, pid); + return std::ranges::find_if(asyncDialogBoxes, [pid](const auto& e) { return e.first == pid; }) != asyncDialogBoxes.end(); +} + +bool CAsyncDialogBox::isPriorityDialogBox(pid_t pid) { + for (const auto& [p, db] : asyncDialogBoxes) { + if (p != pid) + continue; + + return db && db->m_priority; + } + + return false; } CAsyncDialogBox::CAsyncDialogBox(const std::string& title, const std::string& description, std::vector buttons) : @@ -68,7 +79,7 @@ void CAsyncDialogBox::onWrite(int fd, uint32_t mask) { Debug::log(LOG, "CAsyncDialogBox: dialog {:x} hung up, closed."); m_promiseResolver->resolve(m_stdout); - std::erase(asyncDialogBoxes, m_dialogPid); + std::erase_if(asyncDialogBoxes, [this](const auto& e) { return e.first == m_dialogPid; }); wl_event_source_remove(m_readEventSource); m_selfReference.reset(); @@ -112,7 +123,7 @@ SP> CAsyncDialogBox::open() { } m_dialogPid = proc.pid(); - asyncDialogBoxes.emplace_back(m_dialogPid); + asyncDialogBoxes.emplace_back(std::make_pair<>(m_dialogPid, m_selfWeakReference)); // close the write fd, only the dialog owns it now close(outPipe[1]); diff --git a/src/helpers/AsyncDialogBox.hpp b/src/helpers/AsyncDialogBox.hpp index 4018a857d..0ee0144e1 100644 --- a/src/helpers/AsyncDialogBox.hpp +++ b/src/helpers/AsyncDialogBox.hpp @@ -16,6 +16,7 @@ class CAsyncDialogBox { public: static SP create(const std::string& title, const std::string& description, std::vector buttons); static bool isAsyncDialogBox(pid_t pid); + static bool isPriorityDialogBox(pid_t pid); CAsyncDialogBox(const CAsyncDialogBox&) = delete; CAsyncDialogBox(CAsyncDialogBox&&) = delete; @@ -26,7 +27,10 @@ class CAsyncDialogBox { void kill(); bool isRunning() const; - void onWrite(int fd, uint32_t mask); + // focus priority, only permission popups + bool m_priority = false; + + void onWrite(int fd, uint32_t mask); private: CAsyncDialogBox(const std::string& title, const std::string& description, std::vector buttons); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index f9f36cf2a..2d50dbcf1 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -250,7 +250,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (PMONITOR != g_pCompositor->m_lastMonitor && (*PMOUSEFOCUSMON || refocus) && m_forcedFocus.expired()) g_pCompositor->setActiveMonitor(PMONITOR); - if (g_pSessionLockManager->isSessionLocked()) { + // check for windows that have focus priority like our permission popups + pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, FOCUS_PRIORITY); + if (pFoundWindow) + foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); + + if (!foundSurface && g_pSessionLockManager->isSessionLocked()) { // set keyboard focus on session lock surface regardless of layers const auto PSESSIONLOCKSURFACE = g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->m_id); @@ -288,7 +293,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (!forcedFocus) forcedFocus = g_pCompositor->getForceFocus(); - if (forcedFocus) { + if (forcedFocus && !foundSurface) { pFoundWindow = forcedFocus; surfacePos = pFoundWindow->m_realPosition->value(); foundSurface = pFoundWindow->m_wlSurface->resource(); diff --git a/src/managers/permissions/DynamicPermissionManager.cpp b/src/managers/permissions/DynamicPermissionManager.cpp index dd1fd4cf3..c015adfed 100644 --- a/src/managers/permissions/DynamicPermissionManager.cpp +++ b/src/managers/permissions/DynamicPermissionManager.cpp @@ -296,7 +296,8 @@ void CDynamicPermissionManager::askForPermission(wl_client* client, const std::s } else options = {"Deny", "Allow"}; - rule->m_dialogBox = CAsyncDialogBox::create("Permission request", description, options); + rule->m_dialogBox = CAsyncDialogBox::create("Permission request", description, options); + rule->m_dialogBox->m_priority = true; if (!rule->m_dialogBox) { Debug::log(ERR, "CDynamicPermissionManager::askForPermission: hyprland-qtutils likely missing, cannot ask! Disabling permission control...");