diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index b034557e..984db38d 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -312,6 +312,19 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire return; } + if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) { + for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) { + if (!wd->allowsInput()) + continue; + + if (wd->getWindowDecorationRegion().containsPoint(MOUSECOORDS)) { + if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS)) + return; + break; + } + } + } + // if it's a group, add the window if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group && !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged @@ -327,18 +340,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire m_lDwindleNodesData.remove(*PNODE); - const wlr_box box = OPENINGON->pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); - if (wlr_box_contains_point(&box, MOUSECOORDS.x, MOUSECOORDS.y)) { // TODO: Deny when not using mouse - const int SIZE = OPENINGON->pWindow->getGroupSize(); - const int INDEX = (int)((MOUSECOORDS.x - box.x) * 2 * SIZE / box.width + 1) / 2 - 1; - CWindow* pWindowInsertAfter = OPENINGON->pWindow->getGroupWindowByIndex(INDEX); - pWindowInsertAfter->insertWindowToGroup(pWindow); - if (INDEX == -1) - std::swap(pWindow->m_sGroupData.pNextWindow->m_sGroupData.head, pWindow->m_sGroupData.head); - } else { - static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; - (*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - } + static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; + (*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); OPENINGON->pWindow->setGroupCurrent(pWindow); pWindow->applyGroupRules(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 61bc2266..2bbda858 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -254,6 +254,7 @@ void IHyprLayout::onEndDragWindow() { g_pInputManager->unsetCursorImage(); g_pInputManager->currentlyDraggedWindow = nullptr; + g_pInputManager->m_bWasDraggingWindow = true; if (DRAGGINGWINDOW->m_bDraggingTiled) { DRAGGINGWINDOW->m_bIsFloating = false; @@ -265,6 +266,8 @@ void IHyprLayout::onEndDragWindow() { g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pCompositor->focusWindow(DRAGGINGWINDOW); + + g_pInputManager->m_bWasDraggingWindow = false; } void IHyprLayout::onMouseMove(const Vector2D& mousePos) { diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index ebbcc805..6ee88512 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -94,6 +94,19 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); + if (g_pInputManager->m_bWasDraggingWindow) { + for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) { + if (!wd->allowsInput()) + continue; + + if (wd->getWindowDecorationRegion().containsPoint(MOUSECOORDS)) { + if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS)) + return; + break; + } + } + } + // if it's a group, add the window if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group && !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged @@ -109,18 +122,8 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc m_lMasterNodesData.remove(*PNODE); - const wlr_box box = OPENINGON->pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); - if (wlr_box_contains_point(&box, MOUSECOORDS.x, MOUSECOORDS.y)) { // TODO: Deny when not using mouse - const int SIZE = OPENINGON->pWindow->getGroupSize(); - const int INDEX = (int)((MOUSECOORDS.x - box.x) * 2 * SIZE / box.width + 1) / 2 - 1; - CWindow* pWindowInsertAfter = OPENINGON->pWindow->getGroupWindowByIndex(INDEX); - pWindowInsertAfter->insertWindowToGroup(pWindow); - if (INDEX == -1) - std::swap(pWindow->m_sGroupData.pNextWindow->m_sGroupData.head, pWindow->m_sGroupData.head); - } else { - static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; - (*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - } + static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue; + (*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); OPENINGON->pWindow->setGroupCurrent(pWindow); pWindow->applyGroupRules(); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 72e7f24e..23adc165 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1839,25 +1839,22 @@ void CKeybindManager::mouse(std::string args) { const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); - if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords) && pWindow->m_sGroupData.pNextWindow) { - const wlr_box box = pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); - if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) { - const int SIZE = pWindow->getGroupSize(); - pWindow = pWindow->getGroupWindowByIndex((mouseCoords.x - box.x) * SIZE / box.width); + if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords)) { + for (auto& wd : pWindow->m_dWindowDecorations) { + if (!wd->allowsInput()) + continue; - // hack - g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); - if (!pWindow->m_bIsFloating) { - const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked; - g_pKeybindManager->m_bGroupsLocked = true; - g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow); - g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; + if (wd->getWindowDecorationRegion().containsPoint(mouseCoords)) { + wd->onBeginWindowDragOnDeco(mouseCoords); + break; } } } - g_pInputManager->currentlyDraggedWindow = pWindow; - g_pInputManager->dragMode = MBIND_MOVE; + if (!g_pInputManager->currentlyDraggedWindow) + g_pInputManager->currentlyDraggedWindow = pWindow; + + g_pInputManager->dragMode = MBIND_MOVE; g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); } else { g_pKeybindManager->m_bIsMouseBindActive = false; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index b19a929c..40d25858 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -583,16 +583,15 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords); - if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords) && w->m_sGroupData.pNextWindow) { - const wlr_box box = w->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); - if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) { - if (e->state == WLR_BUTTON_PRESSED) { - const int SIZE = w->getGroupSize(); - CWindow* pWindow = w->getGroupWindowByIndex((mouseCoords.x - box.x) * SIZE / box.width); - if (w != pWindow) - w->setGroupCurrent(pWindow); + if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords)) { + for (auto& wd : w->m_dWindowDecorations) { + if (!wd->allowsInput()) + continue; + + if (wd->getWindowDecorationRegion().containsPoint(mouseCoords)) { + wd->onMouseButtonOnDeco(mouseCoords, e); + return; } - return; } } @@ -1625,7 +1624,7 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) { wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; eBorderIconDirection direction = BORDERICON_NONE; wlr_box boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE), - box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)}; + box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)}; if (!wlr_box_contains_point(&boxFullGrabInput, mouseCoords.x, mouseCoords.y) || (!m_lCurrentlyHeldButtons.empty() && !currentlyDraggedWindow)) { direction = BORDERICON_NONE; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index b4d365ee..554f91db 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -7,14 +7,12 @@ #include "../../helpers/Timer.hpp" #include "InputMethodRelay.hpp" -enum eClickBehaviorMode -{ +enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, CLICKMODE_KILL }; -enum eMouseBindMode -{ +enum eMouseBindMode { MBIND_INVALID = -1, MBIND_MOVE = 0, MBIND_RESIZE = 1, @@ -22,8 +20,7 @@ enum eMouseBindMode MBIND_RESIZE_FORCE_RATIO = 3 }; -enum eBorderIconDirection -{ +enum eBorderIconDirection { BORDERICON_NONE, BORDERICON_UP, BORDERICON_DOWN, @@ -118,6 +115,7 @@ class CInputManager { // for dragging floating windows CWindow* currentlyDraggedWindow = nullptr; eMouseBindMode dragMode = MBIND_INVALID; + bool m_bWasDraggingWindow = false; // for refocus to be forced CWindow* m_pForcedFocus = nullptr; diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 4d3200a6..280fe921 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -24,6 +24,7 @@ eDecorationType CHyprGroupBarDecoration::getDecorationType() { constexpr int BAR_INDICATOR_HEIGHT = 3; constexpr int BAR_PADDING_OUTER_VERT = 2; constexpr int BAR_TEXT_PAD = 2; +constexpr int BAR_HORIZONTAL_PADDING = 2; // @@ -93,15 +94,13 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& if (!m_pWindow->m_sSpecialRenderData.decorate) return; - const int PAD = 2; //2px + m_fBarWidth = (m_vLastWindowSize.x - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; - const int BARW = (m_vLastWindowSize.x - PAD * (barsToDraw - 1)) / barsToDraw; - - int xoff = 0; + int xoff = 0; for (int i = 0; i < barsToDraw; ++i) { wlr_box rect = {m_vLastWindowPos.x + xoff - pMonitor->vecPosition.x + offset.x, - m_vLastWindowPos.y - BAR_PADDING_OUTER_VERT - BORDERSIZE - BAR_INDICATOR_HEIGHT - pMonitor->vecPosition.y + offset.y, BARW, BAR_INDICATOR_HEIGHT}; + m_vLastWindowPos.y - BAR_PADDING_OUTER_VERT - BORDERSIZE - BAR_INDICATOR_HEIGHT - pMonitor->vecPosition.y + offset.y, m_fBarWidth, BAR_INDICATOR_HEIGHT}; if (rect.width <= 0 || rect.height <= 0) break; @@ -127,15 +126,15 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle); if (!pTitleTex) - pTitleTex = - m_sTitleTexs.titleTexs - .emplace_back(std::make_unique(m_dwGroupMembers[i], Vector2D{BARW * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale})) - .get(); + pTitleTex = m_sTitleTexs.titleTexs + .emplace_back(std::make_unique(m_dwGroupMembers[i], + Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale})) + .get(); rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * 0.8 * pMonitor->scale; rect.y -= rect.height; - rect.width = BARW * pMonitor->scale; + rect.width = m_fBarWidth * pMonitor->scale; refreshGradients(); @@ -148,7 +147,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f); } - xoff += PAD + BARW; + xoff += BAR_HORIZONTAL_PADDING + m_fBarWidth; } if (*PRENDERTITLES) @@ -305,3 +304,79 @@ void CHyprGroupBarDecoration::refreshGradients() { bool CHyprGroupBarDecoration::allowsInput() { return true; } + +bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D& pos) { + + if (!(!g_pKeybindManager->m_bGroupsLocked // global group lock disengaged + && ((pDraggedWindow->m_eGroupRules & GROUP_INVADE && pDraggedWindow->m_bFirstMap) // window ignore local group locks, or + || (!m_pWindow->getGroupHead()->m_sGroupData.locked // target unlocked + && !(pDraggedWindow->m_sGroupData.pNextWindow && pDraggedWindow->getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group + && !pDraggedWindow->m_sGroupData.deny // source is not denied entry + && !(pDraggedWindow->m_eGroupRules & GROUP_BARRED && pDraggedWindow->m_bFirstMap))) // group rule doesn't prevent adding window + return true; + + const float BARRELATIVEX = pos.x - m_vLastWindowPos.x - m_fBarWidth / 2; + const int WINDOWINDEX = BARRELATIVEX < 0 ? -1 : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); + + CWindow* pWindowInsertAfter = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); + + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pDraggedWindow); + + pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); + + if (WINDOWINDEX == -1) + std::swap(pDraggedWindow->m_sGroupData.head, pDraggedWindow->m_sGroupData.pNextWindow->m_sGroupData.head); + + m_pWindow->setGroupCurrent(pDraggedWindow); + pDraggedWindow->applyGroupRules(); + pDraggedWindow->updateWindowDecos(); + g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow); + + return false; +} + +void CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_pointer_button_event* e) { + if (e->state != WLR_BUTTON_PRESSED) + return; + + const float BARRELATIVEX = pos.x - m_vLastWindowPos.x; + const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); + + if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) { + if (!g_pCompositor->isWindowActive(m_pWindow)) + g_pCompositor->focusWindow(m_pWindow); + return; + } + + CWindow* pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); + + if (pWindow != m_pWindow) + pWindow->setGroupCurrent(pWindow); + + if (!g_pCompositor->isWindowActive(pWindow)) + g_pCompositor->focusWindow(pWindow); +} + +void CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { + const float BARRELATIVEX = pos.x - m_vLastWindowPos.x; + const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); + + if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) + return; + + CWindow* pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); + + // hack + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); + if (!pWindow->m_bIsFloating) { + const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked; + g_pKeybindManager->m_bGroupsLocked = true; + g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow); + g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; + } + + g_pInputManager->currentlyDraggedWindow = pWindow; + + if (!g_pCompositor->isWindowActive(pWindow)) + g_pCompositor->focusWindow(pWindow); +} diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 118c7a64..05736d4b 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -35,6 +35,12 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { virtual bool allowsInput(); + virtual void onBeginWindowDragOnDeco(const Vector2D&); + + virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&); + + virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*); + private: SWindowDecorationExtents m_seExtents; @@ -45,6 +51,8 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { std::deque m_dwGroupMembers; + float m_fBarWidth; + CTitleTex* textureFromTitle(const std::string&); void invalidateTextures(); diff --git a/src/render/decorations/IHyprWindowDecoration.cpp b/src/render/decorations/IHyprWindowDecoration.cpp index a87c334a..e0868b0b 100644 --- a/src/render/decorations/IHyprWindowDecoration.cpp +++ b/src/render/decorations/IHyprWindowDecoration.cpp @@ -28,3 +28,11 @@ CRegion IHyprWindowDecoration::getWindowDecorationRegion() { bool IHyprWindowDecoration::allowsInput() { return false; } + +void IHyprWindowDecoration::onBeginWindowDragOnDeco(const Vector2D&) {} + +bool IHyprWindowDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&) { + return true; +} + +void IHyprWindowDecoration::onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*) {} diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index fec7305d..eadc486f 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -39,6 +39,12 @@ class IHyprWindowDecoration { virtual bool allowsInput(); + virtual void onBeginWindowDragOnDeco(const Vector2D&); // called when the user calls the "movewindow" mouse dispatcher on the deco + + virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&); // returns true if the window should be placed by the layout + + virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*); + private: CWindow* m_pWindow = nullptr; };