diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 62cae8f6..0b2e23a3 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -116,8 +116,8 @@ void CLayerSurface::onDestroy() { void CLayerSurface::onMap() { Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); - mapped = true; - keyboardExclusive = layerSurface->current.interactivity; + mapped = true; + interactivity = layerSurface->current.interactivity; // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -133,12 +133,15 @@ void CLayerSurface::onMap() { surface->resource()->enter(PMONITOR->self.lock()); - if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; + + if (ISEXCLUSIVE) g_pInputManager->m_dExclusiveLSes.push_back(self); - const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && - // don't focus if constrained - (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()); + const bool GRABSFOCUS = ISEXCLUSIVE || + (layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && + // don't focus if constrained + (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())); if (GRABSFOCUS) { // TODO: use the new superb really very cool grab @@ -177,9 +180,6 @@ void CLayerSurface::onUnmap() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); - if (!g_pInputManager->m_dExclusiveLSes.empty()) - g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource()); - if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); @@ -210,33 +210,8 @@ void CLayerSurface::onUnmap() { return; // refocus if needed - if (WASLASTFOCUS) { - g_pInputManager->releaseAllMouseButtons(); - - Vector2D surfaceCoords; - PHLLS pFoundLayerSurface; - SP foundSurface = nullptr; - - g_pCompositor->m_pLastFocus.reset(); - - // find LS-es to focus - foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &surfaceCoords, &pFoundLayerSurface); - - if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &surfaceCoords, &pFoundLayerSurface); - - if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { - // if there isn't any, focus the last window - const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - g_pCompositor->focusWindow(nullptr); - g_pCompositor->focusWindow(PLASTWINDOW); - } else { - // otherwise, full refocus - g_pInputManager->refocus(); - } - } + if (WASLASTFOCUS) + g_pInputManager->refocusLastWindow(PMONITOR); CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); @@ -311,18 +286,36 @@ void CLayerSurface::onCommit() { realSize.setValueAndWarp(geometry.size()); } - if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained - && !keyboardExclusive && mapped) { - g_pCompositor->focusSurface(surface->resource()); + if (mapped) { + const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); + const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; + const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; - const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); - g_pInputManager->m_bEmptyFocusCursorSet = false; - } else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { - g_pInputManager->refocus(); + if (!WASEXCLUSIVE && ISEXCLUSIVE) + g_pInputManager->m_dExclusiveLSes.push_back(self); + else if (WASEXCLUSIVE && !ISEXCLUSIVE) + std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); + + // if the surface was focused and interactive but now isn't, refocus + if (WASLASTFOCUS && !layerSurface->current.interactivity) { + // moveMouseUnified won't focus non interactive layers but it won't unfocus them either, + // so unfocus the surface here. + g_pCompositor->focusSurface(nullptr); + g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID)); + } else if (!WASEXCLUSIVE && !WASLASTFOCUS && + (ISEXCLUSIVE || (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())))) { + // if not focused last and exclusive or accepting input + unconstrained + g_pSeatManager->setGrab(nullptr); + g_pInputManager->releaseAllMouseButtons(); + g_pCompositor->focusSurface(surface->resource()); + + const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); + g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); + g_pInputManager->m_bEmptyFocusCursorSet = false; + } } - keyboardExclusive = layerSurface->current.interactivity; + interactivity = layerSurface->current.interactivity; g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y); @@ -512,4 +505,4 @@ int CLayerSurface::popupsCount() { int no = -1; // we have one dummy popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); return no; -} \ No newline at end of file +} diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 9fa96d2d..056f66a8 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -34,40 +34,41 @@ class CLayerSurface { WP layerSurface; wl_list link; - bool keyboardExclusive = false; + // the header providing the enum type cannot be imported here + int interactivity = 0; - SP surface; + SP surface; - bool mapped = false; - uint32_t layer = 0; + bool mapped = false; + uint32_t layer = 0; - int monitorID = -1; + int monitorID = -1; - bool fadingOut = false; - bool readyToDelete = false; - bool noProcess = false; - bool noAnimations = false; + bool fadingOut = false; + bool readyToDelete = false; + bool noProcess = false; + bool noAnimations = false; - bool forceBlur = false; - bool forceBlurPopups = false; - int xray = -1; - bool ignoreAlpha = false; - float ignoreAlphaValue = 0.f; - bool dimAround = false; + bool forceBlur = false; + bool forceBlurPopups = false; + int xray = -1; + bool ignoreAlpha = false; + float ignoreAlphaValue = 0.f; + bool dimAround = false; - std::optional animationStyle; + std::optional animationStyle; - PHLLSREF self; + PHLLSREF self; - CBox geometry = {0, 0, 0, 0}; - Vector2D position; - std::string szNamespace = ""; - std::unique_ptr popupHead; + CBox geometry = {0, 0, 0, 0}; + Vector2D position; + std::string szNamespace = ""; + std::unique_ptr popupHead; - void onDestroy(); - void onMap(); - void onUnmap(); - void onCommit(); + void onDestroy(); + void onMap(); + void onUnmap(); + void onCommit(); private: struct { @@ -83,4 +84,4 @@ class CLayerSurface { bool operator==(const CLayerSurface& rhs) const { return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID; } -}; \ No newline at end of file +}; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 5ce53472..3e412b27 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -512,7 +512,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 && - allowKeyboardRefocus) { + (allowKeyboardRefocus || pFoundLayerSurface->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)) { g_pCompositor->focusSurface(foundSurface); } @@ -1384,6 +1384,41 @@ void CInputManager::refocus() { mouseMoveUnified(0, true); } +void CInputManager::refocusLastWindow(CMonitor* pMonitor) { + if (!pMonitor) { + refocus(); + return; + } + + Vector2D surfaceCoords; + PHLLS pFoundLayerSurface; + SP foundSurface = nullptr; + + g_pInputManager->releaseAllMouseButtons(); + + // first try for an exclusive layer + if (!m_dExclusiveLSes.empty()) + foundSurface = m_dExclusiveLSes[m_dExclusiveLSes.size() - 1]->surface->resource(); + + // then any surfaces above windows on the same monitor + if (!foundSurface) + foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + &surfaceCoords, &pFoundLayerSurface); + + if (!foundSurface) + foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + &surfaceCoords, &pFoundLayerSurface); + + if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { + // then the last focused window if we're on the same workspace as it + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); + g_pCompositor->focusWindow(PLASTWINDOW); + } else { + // otherwise fall back to a normal refocus. + refocus(); + } +} + void CInputManager::unconstrainMouse() { if (g_pSeatManager->mouse.expired()) return; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 930f3025..8050defe 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -104,6 +104,7 @@ class CInputManager { Vector2D getMouseCoordsInternal(); void refocus(); + void refocusLastWindow(CMonitor* pMonitor); void simulateMouseMovement(); void sendMotionEventsToFocused();