layout: add direction parameter to onWindowCreated and friends (#3269)

* feat(layout): add direction parameter to onWindowCreated and friends

In addition:

- Implement directional moveWindowOutOfGroup for `movewindoworgroup`
  when using dwindle layout. (augmentation of #3006)
- Replace `DWindleLayout::OneTimeFocus` with `IHyprLayout::eDirection`.
- Slight formatting change (clang-format).

* fix: nullptr dereference in dwindle window creation

* refactor: generalized eDirection

* refactor: eliminate DIRECTION_NONE

* Update IHyprLayout.hpp
This commit is contained in:
memchr 2023-09-13 10:13:29 +00:00 committed by GitHub
parent b0d5e4008b
commit 6b1ac659e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 59 deletions

View file

@ -226,7 +226,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
} }
void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) if (pWindow->m_bIsFloating)
return; return;
@ -238,6 +238,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
static auto* const PUSEACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits")->intValue; static auto* const PUSEACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits")->intValue;
static auto* const PDEFAULTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:default_split_ratio")->floatValue; static auto* const PDEFAULTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:default_split_ratio")->floatValue;
if (direction != DIRECTION_DEFAULT && overrideDirection == DIRECTION_DEFAULT)
overrideDirection = direction;
// Populate the node with our window's data // Populate the node with our window's data
PNODE->workspaceID = pWindow->m_iWorkspaceID; PNODE->workspaceID = pWindow->m_iWorkspaceID;
PNODE->pWindow = pWindow; PNODE->pWindow = pWindow;
@ -297,7 +300,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
// last fail-safe to avoid duplicate fullscreens // last fail-safe to avoid duplicate fullscreens
if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) { if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
for (auto& node : m_lDwindleNodesData) { for (auto& node : m_lDwindleNodesData) {
if (node.workspaceID == PNODE->workspaceID && node.pWindow != pWindow) { if (node.workspaceID == PNODE->workspaceID && node.pWindow != nullptr && node.pWindow != pWindow) {
OPENINGON = &node; OPENINGON = &node;
break; break;
} }
@ -372,7 +375,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
bool verticalOverride = false; bool verticalOverride = false;
// let user select position -> top, right, bottom, left // let user select position -> top, right, bottom, left
if (overrideDirection != OneTimeFocus::NOFOCUS) { if (overrideDirection != DIRECTION_DEFAULT) {
// this is horizontal // this is horizontal
if (overrideDirection % 2 == 0) if (overrideDirection % 2 == 0)
@ -391,7 +394,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
// whether or not the override persists after opening one window // whether or not the override persists after opening one window
if (*PERMANENTDIRECTIONOVERRIDE == 0) if (*PERMANENTDIRECTIONOVERRIDE == 0)
overrideDirection = OneTimeFocus::NOFOCUS; overrideDirection = DIRECTION_DEFAULT;
} else if (*PSMARTSPLIT == 1) { } else if (*PSMARTSPLIT == 1) {
const auto tl = NEWPARENT->position; const auto tl = NEWPARENT->position;
const auto tr = NEWPARENT->position + Vector2D(NEWPARENT->size.x, 0); const auto tr = NEWPARENT->position + Vector2D(NEWPARENT->size.x, 0);
@ -994,26 +997,26 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
switch (direction.front()) { switch (direction.front()) {
case 'u': case 'u':
case 't': { case 't': {
overrideDirection = OneTimeFocus::UP; overrideDirection = DIRECTION_UP;
break; break;
} }
case 'd': case 'd':
case 'b': { case 'b': {
overrideDirection = OneTimeFocus::DOWN; overrideDirection = DIRECTION_DOWN;
break; break;
} }
case 'r': { case 'r': {
overrideDirection = OneTimeFocus::RIGHT; overrideDirection = DIRECTION_RIGHT;
break; break;
} }
case 'l': { case 'l': {
overrideDirection = OneTimeFocus::LEFT; overrideDirection = DIRECTION_LEFT;
break; break;
} }
default: { default: {
// any other character resets the focus direction // any other character resets the focus direction
// needed for the persistent mode // needed for the persistent mode
overrideDirection = OneTimeFocus::NOFOCUS; overrideDirection = DIRECTION_DEFAULT;
break; break;
} }
} }

View file

@ -10,15 +10,6 @@
class CHyprDwindleLayout; class CHyprDwindleLayout;
enum eFullscreenMode : uint8_t; enum eFullscreenMode : uint8_t;
enum OneTimeFocus
{
UP = 0,
RIGHT,
DOWN,
LEFT,
NOFOCUS,
};
struct SDwindleNodeData { struct SDwindleNodeData {
SDwindleNodeData* pParent = nullptr; SDwindleNodeData* pParent = nullptr;
bool isNode = false; bool isNode = false;
@ -51,7 +42,7 @@ struct SDwindleNodeData {
class CHyprDwindleLayout : public IHyprLayout { class CHyprDwindleLayout : public IHyprLayout {
public: public:
virtual void onWindowCreatedTiling(CWindow*); virtual void onWindowCreatedTiling(CWindow*, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowRemovedTiling(CWindow*); virtual void onWindowRemovedTiling(CWindow*);
virtual bool isWindowTiled(CWindow*); virtual bool isWindowTiled(CWindow*);
virtual void recalculateMonitor(const int&); virtual void recalculateMonitor(const int&);
@ -90,7 +81,7 @@ class CHyprDwindleLayout : public IHyprLayout {
void toggleSplit(CWindow*); void toggleSplit(CWindow*);
OneTimeFocus overrideDirection = OneTimeFocus::NOFOCUS; eDirection overrideDirection = DIRECTION_DEFAULT;
friend struct SDwindleNodeData; friend struct SDwindleNodeData;
}; };

View file

@ -2,7 +2,7 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
void IHyprLayout::onWindowCreated(CWindow* pWindow) { void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow); onWindowCreatedFloating(pWindow);
} else { } else {
@ -18,7 +18,7 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize;
onWindowCreatedTiling(pWindow); onWindowCreatedTiling(pWindow, direction);
} }
} }

View file

@ -15,8 +15,7 @@ struct SLayoutMessageHeader {
enum eFullscreenMode : uint8_t; enum eFullscreenMode : uint8_t;
enum eRectCorner enum eRectCorner {
{
CORNER_NONE = 0, CORNER_NONE = 0,
CORNER_TOPLEFT, CORNER_TOPLEFT,
CORNER_TOPRIGHT, CORNER_TOPRIGHT,
@ -24,6 +23,14 @@ enum eRectCorner
CORNER_BOTTOMLEFT CORNER_BOTTOMLEFT
}; };
enum eDirection {
DIRECTION_DEFAULT = -1,
DIRECTION_UP = 0,
DIRECTION_RIGHT,
DIRECTION_DOWN,
DIRECTION_LEFT
};
class IHyprLayout { class IHyprLayout {
public: public:
virtual ~IHyprLayout() = 0; virtual ~IHyprLayout() = 0;
@ -35,8 +42,8 @@ class IHyprLayout {
The layout HAS TO set the goal pos and size (anim mgr will use it) The layout HAS TO set the goal pos and size (anim mgr will use it)
If !animationinprogress, then the anim mgr will not apply an anim. If !animationinprogress, then the anim mgr will not apply an anim.
*/ */
virtual void onWindowCreated(CWindow*); virtual void onWindowCreated(CWindow*, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowCreatedTiling(CWindow*) = 0; virtual void onWindowCreatedTiling(CWindow*, eDirection direction = DIRECTION_DEFAULT) = 0;
virtual void onWindowCreatedFloating(CWindow*); virtual void onWindowCreatedFloating(CWindow*);
/* /*

View file

@ -68,7 +68,7 @@ SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) {
return nullptr; return nullptr;
} }
void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) { void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) if (pWindow->m_bIsFloating)
return; return;
@ -294,11 +294,11 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
} }
} }
const float totalSize = (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) ? WSSIZE.x : WSSIZE.y; const float totalSize = (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) ? WSSIZE.x : WSSIZE.y;
const float masterAverageSize = totalSize / MASTERS; const float masterAverageSize = totalSize / MASTERS;
const float slaveAverageSize = totalSize / STACKWINDOWS; const float slaveAverageSize = totalSize / STACKWINDOWS;
float masterAccumulatedSize = 0; float masterAccumulatedSize = 0;
float slaveAccumulatedSize = 0; float slaveAccumulatedSize = 0;
if (*PSMARTRESIZING) { if (*PSMARTRESIZING) {
// check the total width and height so that later // check the total width and height so that later
@ -674,13 +674,13 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1); bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1);
double delta = 0; double delta = 0;
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_vPosition.y + PWINDOW->m_vSize.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y); const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_vPosition.y + PWINDOW->m_vSize.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x); const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y); const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x); const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT; const bool LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT;
const bool TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT; const bool TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT;
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 && !centered) if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 && !centered)
return; return;
@ -732,19 +732,18 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
nodesInSameColumn /= 2; nodesInSameColumn /= 2;
if (RESIZEDELTA != 0 && nodesInSameColumn > 1) { if (RESIZEDELTA != 0 && nodesInSameColumn > 1) {
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE); const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
const auto REVNODEIT = std::find(m_lMasterNodesData.rbegin(), m_lMasterNodesData.rend(), *PNODE); const auto REVNODEIT = std::find(m_lMasterNodesData.rbegin(), m_lMasterNodesData.rend(), *PNODE);
const auto SIZE = isStackVertical ? const auto SIZE = isStackVertical ? (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / nodesInSameColumn :
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / nodesInSameColumn: (PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) / nodesInSameColumn;
(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) / nodesInSameColumn;
const float totalSize = isStackVertical ? WSSIZE.y : WSSIZE.x; const float totalSize = isStackVertical ? WSSIZE.y : WSSIZE.x;
const float minSize = totalSize / nodesInSameColumn * 0.2; const float minSize = totalSize / nodesInSameColumn * 0.2;
const bool resizePrevNodes = isStackVertical ? (TOP || DISPLAYBOTTOM) && !DISPLAYTOP : (LEFT || DISPLAYRIGHT) && !DISPLAYLEFT; const bool resizePrevNodes = isStackVertical ? (TOP || DISPLAYBOTTOM) && !DISPLAYTOP : (LEFT || DISPLAYRIGHT) && !DISPLAYLEFT;
int nodesLeft = 0; int nodesLeft = 0;
float sizeLeft = 0; float sizeLeft = 0;
int nodeCount = 0; int nodeCount = 0;
// check the sizes of all the nodes to be resized for later calculation // check the sizes of all the nodes to be resized for later calculation
auto checkNodesLeft = [&sizeLeft, &nodesLeft, orientation, isStackVertical, &nodeCount, PNODE](auto it) { auto checkNodesLeft = [&sizeLeft, &nodesLeft, orientation, isStackVertical, &nodeCount, PNODE](auto it) {
if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID) if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID)
@ -773,17 +772,16 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
PNODE->percSize += resizeDiff / SIZE; PNODE->percSize += resizeDiff / SIZE;
// resize the other nodes // resize the other nodes
nodeCount = 0; nodeCount = 0;
auto resizeNodesLeft = [maxSizeIncrease, resizeDiff, minSize, orientation, isStackVertical, SIZE, &nodeCount, nodesLeft, PNODE](auto &it) { auto resizeNodesLeft = [maxSizeIncrease, resizeDiff, minSize, orientation, isStackVertical, SIZE, &nodeCount, nodesLeft, PNODE](auto& it) {
if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID) if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID)
return; return;
nodeCount++; nodeCount++;
// if center orientation, only resize when on the same side // if center orientation, only resize when on the same side
if (!it.isMaster && orientation == ORIENTATION_CENTER && nodeCount % 2 == 1) if (!it.isMaster && orientation == ORIENTATION_CENTER && nodeCount % 2 == 1)
return; return;
const float size = isStackVertical ? it.size.y : it.size.x; const float size = isStackVertical ? it.size.y : it.size.x;
const float resizeDeltaForEach = maxSizeIncrease != 0 ? const float resizeDeltaForEach = maxSizeIncrease != 0 ? resizeDiff * (size - minSize) / maxSizeIncrease : resizeDiff / nodesLeft;
resizeDiff * (size - minSize) / maxSizeIncrease : resizeDiff / nodesLeft;
it.percSize -= resizeDeltaForEach / SIZE; it.percSize -= resizeDeltaForEach / SIZE;
}; };
if (resizePrevNodes) { if (resizePrevNodes) {

View file

@ -48,7 +48,7 @@ struct SMasterWorkspaceData {
class CHyprMasterLayout : public IHyprLayout { class CHyprMasterLayout : public IHyprLayout {
public: public:
virtual void onWindowCreatedTiling(CWindow*); virtual void onWindowCreatedTiling(CWindow*, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowRemovedTiling(CWindow*); virtual void onWindowRemovedTiling(CWindow*);
virtual bool isWindowTiled(CWindow*); virtual bool isWindowTiled(CWindow*);
virtual void recalculateMonitor(const int&); virtual void recalculateMonitor(const int&);

View file

@ -1963,9 +1963,20 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi
g_pCompositor->warpCursorTo(pWindow->middle()); g_pCompositor->warpCursorTo(pWindow->middle());
} }
void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow) { void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) {
static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("misc:group_focus_removed_window")->intValue; static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("misc:group_focus_removed_window")->intValue;
const auto PWINDOWPREV = pWindow->getGroupPrevious(); const auto PWINDOWPREV = pWindow->getGroupPrevious();
eDirection direction;
switch (dir[0]) {
case 't':
case 'u': direction = DIRECTION_UP; break;
case 'd':
case 'b': direction = DIRECTION_DOWN; break;
case 'l': direction = DIRECTION_LEFT; break;
case 'r': direction = DIRECTION_RIGHT; break;
default: direction = DIRECTION_DEFAULT;
}
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow);
@ -1973,7 +1984,7 @@ void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow) {
g_pKeybindManager->m_bGroupsLocked = true; g_pKeybindManager->m_bGroupsLocked = true;
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow); g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow, direction);
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
@ -2059,13 +2070,13 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
} else if (PWINDOWINDIR) { } else if (PWINDOWINDIR) {
if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED)) if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED))
moveWindowOutOfGroup(PWINDOW); moveWindowOutOfGroup(PWINDOW, args);
else { else {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle()); g_pCompositor->warpCursorTo(PWINDOW->middle());
} }
} else if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED)) { } else if (ISWINDOWGROUP && (*BIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED)) {
moveWindowOutOfGroup(PWINDOW); moveWindowOutOfGroup(PWINDOW, args);
} }
} }

View file

@ -91,7 +91,7 @@ class CKeybindManager {
bool ensureMouseBindState(); bool ensureMouseBindState();
static bool tryMoveFocusToMonitor(CMonitor* monitor); static bool tryMoveFocusToMonitor(CMonitor* monitor);
static void moveWindowOutOfGroup(CWindow* pWindow); static void moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir = "");
static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection); static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection);
static void switchToWindow(CWindow* PWINDOWTOCHANGETO); static void switchToWindow(CWindow* PWINDOWTOCHANGETO);