summaryrefslogtreecommitdiff
path: root/src/layout/MasterLayout.cpp
diff options
context:
space:
mode:
authorvaxerski <43317083+vaxerski@users.noreply.github.com>2022-07-16 15:57:31 +0200
committervaxerski <43317083+vaxerski@users.noreply.github.com>2022-07-16 15:57:31 +0200
commit5c836e6460ae5e8c290cfff61ec0d2d0e99dfa15 (patch)
treebb38dedd586738f0a1fe37b9a4234b754f54541d /src/layout/MasterLayout.cpp
parent48e5bd96bc71f94f774eb92b00ef560b2f911c73 (diff)
added master layout
Diffstat (limited to 'src/layout/MasterLayout.cpp')
-rw-r--r--src/layout/MasterLayout.cpp421
1 files changed, 421 insertions, 0 deletions
diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp
new file mode 100644
index 00000000..f88ee08f
--- /dev/null
+++ b/src/layout/MasterLayout.cpp
@@ -0,0 +1,421 @@
+#include "MasterLayout.hpp"
+#include "../Compositor.hpp"
+
+SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(CWindow* pWindow) {
+ for (auto& nd : m_lMasterNodesData) {
+ if (nd.pWindow == pWindow)
+ return &nd;
+ }
+
+ return nullptr;
+}
+
+int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
+ int no = 0;
+ for (auto& n : m_lMasterNodesData) {
+ if (n.workspaceID == ws)
+ no++;
+ }
+
+ return no;
+}
+
+std::string CHyprMasterLayout::getLayoutName() {
+ return "Master";
+}
+
+SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) {
+ for (auto& n : m_lMasterNodesData) {
+ if (n.isMaster && n.workspaceID == ws)
+ return &n;
+ }
+
+ return nullptr;
+}
+
+void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
+ if (pWindow->m_bIsFloating)
+ return;
+
+ const auto PNODE = &m_lMasterNodesData.emplace_back();
+
+ PNODE->workspaceID = pWindow->m_iWorkspaceID;
+ PNODE->pWindow = pWindow;
+
+ static auto *const PNEWISMASTER = &g_pConfigManager->getConfigValuePtr("master:new_is_master")->intValue;
+
+ const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID);
+ float lastSplitPercent = 0.5f;
+
+ if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1) {
+ for (auto& nd : m_lMasterNodesData) {
+ if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
+ nd.isMaster = false;
+ lastSplitPercent = nd.percMaster;
+ break;
+ }
+ }
+
+ PNODE->isMaster = true;
+ PNODE->percMaster = lastSplitPercent;
+ } else {
+ PNODE->isMaster = false;
+ }
+
+ // recalc
+ recalculateMonitor(pWindow->m_iMonitorID);
+}
+
+void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
+ const auto PNODE = getNodeFromWindow(pWindow);
+
+ if (!PNODE)
+ return;
+
+ if (PNODE->isMaster) {
+ // find new one
+ for (auto& nd : m_lMasterNodesData) {
+ if (!nd.isMaster) {
+ nd.isMaster = true;
+ break;
+ }
+ }
+ }
+
+ m_lMasterNodesData.remove(*PNODE);
+
+ recalculateMonitor(pWindow->m_iMonitorID);
+}
+
+void CHyprMasterLayout::recalculateMonitor(const int& monid) {
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
+
+ if (!PWORKSPACE)
+ return;
+
+ g_pHyprRenderer->damageMonitor(PMONITOR);
+
+ if (PMONITOR->specialWorkspaceOpen) {
+ calculateWorkspace(SPECIAL_WORKSPACE_ID);
+ }
+
+ if (PWORKSPACE->m_bHasFullscreenWindow) {
+ if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL)
+ return;
+
+ // massive hack from the fullscreen func
+ const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
+
+ SMasterNodeData fakeNode;
+ fakeNode.pWindow = PFULLWINDOW;
+ fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
+ fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
+ fakeNode.workspaceID = PWORKSPACE->m_iID;
+ PFULLWINDOW->m_vPosition = fakeNode.position;
+ PFULLWINDOW->m_vSize = fakeNode.size;
+
+ applyNodeDataToWindow(&fakeNode);
+
+ return;
+ }
+
+ // calc the WS
+ calculateWorkspace(PWORKSPACE->m_iID);
+}
+
+void CHyprMasterLayout::calculateWorkspace(const int& ws) {
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(ws);
+
+ if (!PWORKSPACE)
+ return;
+
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
+
+ const auto PMASTERNODE = getMasterNodeOnWorkspace(PWORKSPACE->m_iID);
+
+ if (!PMASTERNODE)
+ return;
+
+ if (getNodesOnWorkspace(PWORKSPACE->m_iID) < 2) {
+ PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
+ PMASTERNODE->size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
+ applyNodeDataToWindow(PMASTERNODE);
+ return;
+ } else {
+ PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
+ PMASTERNODE->size = Vector2D((PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
+ }
+
+ const auto SLAVESIZE = 1.f / (getNodesOnWorkspace(PWORKSPACE->m_iID) - 1) * (PMASTERNODE->size.y);
+ int slavesDone = 0;
+
+ for (auto& nd : m_lMasterNodesData) {
+ if (nd.workspaceID != PWORKSPACE->m_iID)
+ continue;
+
+ if (nd == *PMASTERNODE) {
+ applyNodeDataToWindow(PMASTERNODE);
+ continue;
+ }
+
+ nd.position = Vector2D(PMASTERNODE->size.x + PMASTERNODE->position.x, slavesDone * SLAVESIZE + PMASTERNODE->position.y);
+ nd.size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x, SLAVESIZE);
+
+ slavesDone++;
+
+ applyNodeDataToWindow(&nd);
+ }
+}
+
+void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
+ SMonitor* PMONITOR = nullptr;
+
+ if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) {
+ for (auto& m : g_pCompositor->m_vMonitors) {
+ if (m->specialWorkspaceOpen) {
+ PMONITOR = m.get();
+ break;
+ }
+ }
+ } else {
+ PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID);
+ }
+
+ if (!PMONITOR) {
+ Debug::log(ERR, "Orphaned Node %x (workspace ID: %i)!!", pNode, pNode->workspaceID);
+ return;
+ }
+
+ // for gaps outer
+ const bool DISPLAYLEFT = STICKS(pNode->position.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
+ const bool DISPLAYRIGHT = STICKS(pNode->position.x + pNode->size.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
+ const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
+ const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
+
+ const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
+ const auto GAPSIN = g_pConfigManager->getInt("general:gaps_in");
+ const auto GAPSOUT = g_pConfigManager->getInt("general:gaps_out");
+
+ const auto PWINDOW = pNode->pWindow;
+
+ if (!g_pCompositor->windowValidMapped(PWINDOW)) {
+ Debug::log(ERR, "Node %x holding invalid window %x!!", pNode, PWINDOW);
+ return;
+ }
+
+ PWINDOW->m_vSize = pNode->size;
+ PWINDOW->m_vPosition = pNode->position;
+
+ // TODO: special
+
+ auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
+ auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
+
+ const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
+ DISPLAYTOP ? GAPSOUT : GAPSIN);
+
+ const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? GAPSOUT : GAPSIN,
+ DISPLAYBOTTOM ? GAPSOUT : GAPSIN);
+
+ calcPos = calcPos + OFFSETTOPLEFT;
+ calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
+
+ if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) {
+ static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
+
+ PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
+ PWINDOW->m_vRealSize = calcSize * *PSCALEFACTOR;
+
+ g_pXWaylandManager->setWindowSize(PWINDOW, calcSize * *PSCALEFACTOR);
+ } else {
+ PWINDOW->m_vRealSize = calcSize;
+ PWINDOW->m_vRealPosition = calcPos;
+
+ g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
+ }
+
+ PWINDOW->updateWindowDecos();
+}
+
+bool CHyprMasterLayout::isWindowTiled(CWindow* pWindow) {
+ return getNodeFromWindow(pWindow) != nullptr;
+}
+
+void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* pWindow) {
+ const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
+
+ if (!g_pCompositor->windowValidMapped(PWINDOW))
+ return;
+
+ const auto PNODE = getNodeFromWindow(PWINDOW);
+
+ if (!PNODE) {
+ PWINDOW->m_vRealSize = Vector2D(std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999));
+ PWINDOW->updateWindowDecos();
+ return;
+ }
+
+ // get master
+ const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
+
+ if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
+ return;
+
+ float delta = pixResize.x / PMONITOR->vecSize.x;
+
+ PMASTER->percMaster += delta;
+
+ std::clamp(PMASTER->percMaster, 0.05f, 0.95f);
+
+ recalculateMonitor(PMONITOR->ID);
+}
+
+void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
+ if (!g_pCompositor->windowValidMapped(pWindow))
+ return;
+
+ if (on == pWindow->m_bIsFullscreen)
+ return; // ignore
+
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
+
+ if (PWORKSPACE->m_bHasFullscreenWindow && on) {
+ // if the window wants to be fullscreen but there already is one,
+ // ignore the request.
+ return;
+ }
+
+ // otherwise, accept it.
+ pWindow->m_bIsFullscreen = on;
+ PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
+
+ g_pEventManager->postEvent(SHyprIPCEvent("fullscreen", std::to_string((int)on)));
+
+ if (!pWindow->m_bIsFullscreen) {
+ // if it got its fullscreen disabled, set back its node if it had one
+ const auto PNODE = getNodeFromWindow(pWindow);
+ if (PNODE)
+ applyNodeDataToWindow(PNODE);
+ else {
+ // get back its' dimensions from position and size
+ pWindow->m_vRealPosition = pWindow->m_vPosition;
+ pWindow->m_vRealSize = pWindow->m_vSize;
+ }
+ } else {
+ // if it now got fullscreen, make it fullscreen
+
+ PWORKSPACE->m_efFullscreenMode = fullscreenMode;
+
+ // save position and size if floating
+ if (pWindow->m_bIsFloating) {
+ pWindow->m_vPosition = pWindow->m_vRealPosition.vec();
+ pWindow->m_vSize = pWindow->m_vRealSize.vec();
+ }
+
+ // apply new pos and size being monitors' box
+ if (fullscreenMode == FULLSCREEN_FULL) {
+ pWindow->m_vRealPosition = PMONITOR->vecPosition;
+ pWindow->m_vRealSize = PMONITOR->vecSize;
+ } else {
+ // This is a massive hack.
+ // We make a fake "only" node and apply
+ // To keep consistent with the settings without C+P code
+
+ SMasterNodeData fakeNode;
+ fakeNode.pWindow = pWindow;
+ fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
+ fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
+ fakeNode.workspaceID = pWindow->m_iWorkspaceID;
+ pWindow->m_vPosition = fakeNode.position;
+ pWindow->m_vSize = fakeNode.size;
+
+ applyNodeDataToWindow(&fakeNode);
+ }
+ }
+
+ g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
+
+ g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
+
+ g_pCompositor->moveWindowToTop(pWindow);
+
+ // we need to fix XWayland windows by sending them to NARNIA
+ // because otherwise they'd still be recieving mouse events
+ g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
+
+ recalculateMonitor(PMONITOR->ID);
+}
+
+void CHyprMasterLayout::recalculateWindow(CWindow* pWindow) {
+ const auto PNODE = getNodeFromWindow(pWindow);
+
+ if (!PNODE)
+ return;
+
+ recalculateMonitor(pWindow->m_iMonitorID);
+}
+
+SWindowRenderLayoutHints CHyprMasterLayout::requestRenderHints(CWindow* pWindow) {
+ // window should be valid, insallah
+
+ SWindowRenderLayoutHints hints;
+
+ return hints; // master doesnt have any hints
+}
+
+void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
+ // windows should be valid, insallah
+
+ const auto PNODE = getNodeFromWindow(pWindow);
+ const auto PNODE2 = getNodeFromWindow(pWindow2);
+
+ if (!PNODE2 || !PNODE)
+ return;
+
+ if (PNODE->workspaceID != PNODE2->workspaceID) {
+ Debug::log(ERR, "Master: Rejecting a swap between workspaces");
+ return;
+ }
+
+ // massive hack: just swap window pointers, lol
+ const auto PWINDOW1 = PNODE->pWindow;
+ PNODE->pWindow = PNODE2->pWindow;
+ PNODE2->pWindow = PWINDOW1;
+
+ recalculateMonitor(PWINDOW1->m_iMonitorID);
+}
+
+void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
+ // window should be valid, insallah
+
+ const auto PNODE = getNodeFromWindow(pWindow);
+
+ if (!PNODE)
+ return;
+
+ const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID);
+
+ PMASTER->percMaster = std::clamp(PMASTER->percMaster + ratio, 0.05f, 0.95f);
+
+ recalculateMonitor(pWindow->m_iMonitorID);
+}
+
+std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
+ return "";
+}
+
+void CHyprMasterLayout::onEnable() {
+ for (auto& w : g_pCompositor->m_vWindows) {
+ if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->m_bHidden)
+ continue;
+
+ onWindowCreatedTiling(w.get());
+ }
+}
+
+void CHyprMasterLayout::onDisable() {
+ m_lMasterNodesData.clear();
+} \ No newline at end of file