diff --git a/example/hypr.conf b/example/hypr.conf index 929c875..ebba2fb 100644 --- a/example/hypr.conf +++ b/example/hypr.conf @@ -8,6 +8,7 @@ border_size=1 gaps_out=20 rounding=0 max_fps=60 # max fps for updates of config & animations +layout=0 # 0 - dwindle (default), 1 - master # Execs diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 2771a3c..7ba68ab 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -15,6 +15,8 @@ void ConfigManager::init() { configValues["gaps_out"].intValue = 20; configValues["rounding"].intValue = 5; + configValues["layout"].intValue = LAYOUT_DWINDLE; + configValues["max_fps"].intValue = 60; configValues["bar:monitor"].intValue = 0; @@ -324,7 +326,8 @@ void ConfigManager::loadConfigLoadVars() { ifs.close(); } - g_pWindowManager->setAllWindowsDirty(); + // recalc all workspaces + g_pWindowManager->recalcAllWorkspaces(); // Reload the bar as well, don't load it before the default is loaded. if (loadBar && g_pWindowManager->statusBar) { @@ -332,6 +335,12 @@ void ConfigManager::loadConfigLoadVars() { g_pWindowManager->statusBar->setup(configValues["bar:monitor"].intValue); } + // Ensure correct layout + if (configValues["layout"].intValue < 0 || configValues["layout"].intValue > 1) { + Debug::log(ERR, "Invalid layout ID, falling back to 0."); + configValues["layout"].intValue = 0; + } + loadBar = true; isFirstLaunch = false; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 18bdd28..a7b96b8 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -3,6 +3,11 @@ #include #include "../utilities/Debug.hpp" +enum ELayouts { + LAYOUT_DWINDLE = 0, + LAYOUT_MASTER +}; + struct SConfigValue { int64_t intValue = -1; float floatValue = -1; diff --git a/src/events/events.cpp b/src/events/events.cpp index 0ea1296..5d85e06 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -280,17 +280,28 @@ CWindow* Events::remapWindow(int windowID, bool wasfloating, int forcemonitor) { window.setParentNodeID(0); } - // Also sets the old one - g_pWindowManager->calculateNewWindowParams(&window); + // For master layout, add the index + window.setMasterChildIndex(g_pWindowManager->getWindowsOnWorkspace(g_pWindowManager->activeWorkspaces[CURRENTSCREEN]) - 1); + // and set master if needed + if (g_pWindowManager->getWindowsOnWorkspace(g_pWindowManager->activeWorkspaces[CURRENTSCREEN]) == 0) + window.setMaster(true); - // Set real size. No animations in the beginning. Maybe later. TODO? - window.setRealPosition(window.getEffectivePosition()); - window.setRealSize(window.getEffectiveSize()); // Add to arr g_pWindowManager->addWindowToVectorSafe(window); - Debug::log(LOG, "Created a new tiled window! X: " + std::to_string(window.getPosition().x) + ", Y: " + std::to_string(window.getPosition().y) + ", W: " + std::to_string(window.getSize().x) + ", H:" + std::to_string(window.getSize().y) + " ID: " + std::to_string(windowID)); + // Now we need to modify the copy in the array. + const auto PWINDOWINARR = g_pWindowManager->getWindowFromDrawable(windowID); + + + // Also sets the old one + g_pWindowManager->calculateNewWindowParams(PWINDOWINARR); + + // Set real size. No animations in the beginning. Maybe later. TODO? + PWINDOWINARR->setRealPosition(PWINDOWINARR->getEffectivePosition()); + PWINDOWINARR->setRealSize(PWINDOWINARR->getEffectiveSize()); + + Debug::log(LOG, "Created a new tiled window! X: " + std::to_string(PWINDOWINARR->getPosition().x) + ", Y: " + std::to_string(PWINDOWINARR->getPosition().y) + ", W: " + std::to_string(PWINDOWINARR->getSize().x) + ", H:" + std::to_string(PWINDOWINARR->getSize().y) + " ID: " + std::to_string(windowID)); // Set map values g_pWindowManager->Values[0] = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE; @@ -301,7 +312,7 @@ CWindow* Events::remapWindow(int windowID, bool wasfloating, int forcemonitor) { // Make all floating windows above g_pWindowManager->setAllFloatingWindowsTop(); - return g_pWindowManager->getWindowFromDrawable(windowID); + return PWINDOWINARR; } void Events::eventMapWindow(xcb_generic_event_t* event) { diff --git a/src/window.cpp b/src/window.cpp index 620aabd..74fb3f2 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,7 +1,7 @@ #include "window.hpp" #include "windowManager.hpp" -CWindow::CWindow() { this->setCanKill(false); this->setImmovable(false); this->setNoInterventions(false); this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); this->setName(""); } +CWindow::CWindow() { this->setDead(false); this->setMasterChildIndex(0); this->setMaster(false); this->setCanKill(false); this->setImmovable(false); this->setNoInterventions(false); this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); this->setName(""); } CWindow::~CWindow() { } void CWindow::generateNodeID() { diff --git a/src/window.hpp b/src/window.hpp index d2d47d1..dc74fbb 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -39,6 +39,7 @@ public: EXPOSED_MEMBER(Dirty, bool, b); void setDirtyRecursive(bool); + // ONLY for dwindle layout! void recalcSizePosRecursive(); EXPOSED_MEMBER(Size, Vector2D, vec); @@ -69,6 +70,11 @@ public: // ICCCM EXPOSED_MEMBER(CanKill, bool, b); + + // Master layout + EXPOSED_MEMBER(Master, bool, b); + EXPOSED_MEMBER(MasterChildIndex, int, i); + EXPOSED_MEMBER(Dead, bool, b); private: diff --git a/src/windowManager.cpp b/src/windowManager.cpp index faffa36..f70f01e 100644 --- a/src/windowManager.cpp +++ b/src/windowManager.cpp @@ -732,50 +732,171 @@ void CWindowManager::calculateNewTileSetOldTile(CWindow* pWindow) { // Get the parent and both children, one of which will be pWindow const auto PPARENT = getWindowFromDrawable(pWindow->getParentNodeID()); + const auto PMONITOR = getMonitorFromWindow(pWindow); + if (!PMONITOR) { + Debug::log(ERR, "Monitor was nullptr! (calculateNewTileSetOldTile)"); + return; + } + if (!PPARENT) { // New window on this workspace. // Open a fullscreen window. - const auto MONITOR = getMonitorFromWindow(pWindow); - if (!MONITOR) { - Debug::log(ERR, "Monitor was nullptr! (calculateNewTileSetOldTile)"); - return; - } - - pWindow->setSize(Vector2D(MONITOR->vecSize.x, MONITOR->vecSize.y)); - pWindow->setPosition(Vector2D(MONITOR->vecPosition.x, MONITOR->vecPosition.y)); + + pWindow->setSize(Vector2D(PMONITOR->vecSize.x, PMONITOR->vecSize.y)); + pWindow->setPosition(Vector2D(PMONITOR->vecPosition.x, PMONITOR->vecPosition.y)); return; } - // Get the sibling - const auto PSIBLING = getWindowFromDrawable(PPARENT->getChildNodeAID() == pWindow->getDrawable() ? PPARENT->getChildNodeBID() : PPARENT->getChildNodeAID()); - // Should NEVER be null - if (PSIBLING) { - const auto PLASTSIZE = PPARENT->getSize(); - const auto PLASTPOS = PPARENT->getPosition(); + switch (ConfigManager::getInt("layout")) + { + case LAYOUT_DWINDLE: + { + // Get the sibling + const auto PSIBLING = getWindowFromDrawable(PPARENT->getChildNodeAID() == pWindow->getDrawable() ? PPARENT->getChildNodeBID() : PPARENT->getChildNodeAID()); - if (PLASTSIZE.x > PLASTSIZE.y) { - PSIBLING->setPosition(Vector2D(PLASTPOS.x, PLASTPOS.y)); - PSIBLING->setSize(Vector2D(PLASTSIZE.x / 2.f, PLASTSIZE.y)); - pWindow->setSize(Vector2D(PLASTSIZE.x / 2.f, PLASTSIZE.y)); - pWindow->setPosition(Vector2D(PLASTPOS.x + PLASTSIZE.x / 2.f, PLASTPOS.y)); - } else { - PSIBLING->setPosition(Vector2D(PLASTPOS.x, PLASTPOS.y)); - PSIBLING->setSize(Vector2D(PLASTSIZE.x, PLASTSIZE.y / 2.f)); - pWindow->setSize(Vector2D(PLASTSIZE.x, PLASTSIZE.y / 2.f)); - pWindow->setPosition(Vector2D(PLASTPOS.x, PLASTPOS.y + PLASTSIZE.y / 2.f)); + // Should NEVER be null + if (PSIBLING) { + const auto PLASTSIZE = PPARENT->getSize(); + const auto PLASTPOS = PPARENT->getPosition(); + if (PLASTSIZE.x > PLASTSIZE.y) { + PSIBLING->setPosition(Vector2D(PLASTPOS.x, PLASTPOS.y)); + PSIBLING->setSize(Vector2D(PLASTSIZE.x / 2.f, PLASTSIZE.y)); + pWindow->setSize(Vector2D(PLASTSIZE.x / 2.f, PLASTSIZE.y)); + pWindow->setPosition(Vector2D(PLASTPOS.x + PLASTSIZE.x / 2.f, PLASTPOS.y)); + } else { + PSIBLING->setPosition(Vector2D(PLASTPOS.x, PLASTPOS.y)); + PSIBLING->setSize(Vector2D(PLASTSIZE.x, PLASTSIZE.y / 2.f)); + pWindow->setSize(Vector2D(PLASTSIZE.x, PLASTSIZE.y / 2.f)); + pWindow->setPosition(Vector2D(PLASTPOS.x, PLASTPOS.y + PLASTSIZE.y / 2.f)); + } + + PSIBLING->setDirty(true); + } else { + Debug::log(ERR, "Sibling node was null?? pWindow x,y,w,h: " + std::to_string(pWindow->getPosition().x) + " " + std::to_string(pWindow->getPosition().y) + " " + std::to_string(pWindow->getSize().x) + " " + std::to_string(pWindow->getSize().y)); + } } + break; + + case LAYOUT_MASTER: + { + recalcEntireWorkspace(pWindow->getWorkspaceID()); + } + break; + } +} - PSIBLING->setDirty(true); - } else { - Debug::log(ERR, "Sibling node was null?? pWindow x,y,w,h: " + std::to_string(pWindow->getPosition().x) + " " - + std::to_string(pWindow->getPosition().y) + " " + std::to_string(pWindow->getSize().x) + " " - + std::to_string(pWindow->getSize().y)); +int CWindowManager::getWindowsOnWorkspace(const int& workspace) { + int number = 0; + for (auto& w : windows) { + if (w.getWorkspaceID() == workspace && w.getDrawable() > 0) { + ++number; + } } - Values[0] = XCB_STACK_MODE_BELOW; - xcb_configure_window(DisplayConnection, pWindow->getDrawable(), XCB_CONFIG_WINDOW_STACK_MODE, Values); + return number; +} + +SMonitor* CWindowManager::getMonitorFromWorkspace(const int& workspace) { + int monitorID = -1; + for (auto& work : workspaces) { + if (work.getID() == workspace) { + monitorID = work.getMonitor(); + break; + } + } + + for (auto& monitor : monitors) { + if (monitor.ID == monitorID) { + return &monitor; + } + } + + return nullptr; +} + +void CWindowManager::recalcEntireWorkspace(const int& workspace) { + + switch (ConfigManager::getInt("layout")) + { + case LAYOUT_MASTER: + { + // Get the monitor + const auto PMONITOR = getMonitorFromWorkspace(workspace); + + // first, calc the size + CWindow* pMaster = nullptr; + for (auto& w : windows) { + if (w.getWorkspaceID() == workspace && w.getMaster() && !w.getDead()) { + pMaster = &w; + break; + } + } + + if (!pMaster) { + Debug::log(ERR, "No master found on workspace???"); + return; + } + + // set the xy for master + pMaster->setPosition(Vector2D(0, 0) + PMONITOR->vecPosition); + pMaster->setSize(Vector2D(PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y)); + + // get children sorted + std::vector children; + for (auto& w : windows) { + if (w.getWorkspaceID() == workspace && !w.getMaster() && w.getDrawable() > 0 && !w.getDead()) + children.push_back(&w); + } + std::sort(children.begin(), children.end(), [](CWindow*& a, CWindow*& b) { + return a->getMasterChildIndex() < b->getMasterChildIndex(); + }); + + // if no children, master full + if (children.size() == 0) { + pMaster->setPosition(Vector2D(0, 0) + PMONITOR->vecPosition); + pMaster->setSize(Vector2D(PMONITOR->vecSize.x, PMONITOR->vecSize.y)); + } + + // Children sorted, set xy + int yoff = 0; + for (const auto& child : children) { + child->setPosition(Vector2D(PMONITOR->vecSize.x / 2, yoff) + PMONITOR->vecPosition); + child->setSize(Vector2D(PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y / children.size())); + + yoff += PMONITOR->vecSize.y / children.size(); + } + + // done + setAllWorkspaceWindowsDirtyByID(workspace); + } + break; + + case LAYOUT_DWINDLE: + { + // get the master on the workspace + CWindow* pMasterWindow = nullptr; + for (auto& w : windows) { + if (w.getWorkspaceID() == workspace && w.getParentNodeID() == 0) { + pMasterWindow = &w; + break; + } + } + + if (!pMasterWindow) { + return; + } + + pMasterWindow->recalcSizePosRecursive(); + setAllWorkspaceWindowsDirtyByID(workspace); + } + break; + + default: + break; + } + } void CWindowManager::calculateNewFloatingWindow(CWindow* pWindow) { @@ -906,6 +1027,45 @@ void CWindowManager::closeWindowAllChecks(int64_t id) { g_pWindowManager->removeWindowFromVectorSafe(id); } +void CWindowManager::fixMasterWorkspaceOnClosed(CWindow* pWindow) { + // get children and master + CWindow* pMaster = nullptr; + for (auto& w : windows) { + if (w.getWorkspaceID() == pWindow->getWorkspaceID() && w.getMaster()) { + pMaster = &w; + break; + } + } + + if (!pMaster) { + Debug::log(ERR, "No master found on workspace???"); + return; + } + + // get children sorted + std::vector children; + for (auto& w : windows) { + if (w.getWorkspaceID() == pWindow->getWorkspaceID() && !w.getMaster() && w.getDrawable() > 0 && w.getDrawable() != pWindow->getDrawable()) + children.push_back(&w); + } + std::sort(children.begin(), children.end(), [](CWindow*& a, CWindow*& b) { + return a->getMasterChildIndex() < b->getMasterChildIndex(); + }); + + // If closed window was master, set a new master. + if (pWindow->getMaster()) { + if (children.size() > 0) { + children[0]->setMaster(true); + } + } else { + // else fix the indices + for (long unsigned int i = pWindow->getMasterChildIndex() - 1; i < children.size(); ++i) { + // masterChildIndex = 1 for the first child + children[i]->setMasterChildIndex(i); + } + } +} + void CWindowManager::fixWindowOnClose(CWindow* pClosedWindow) { if (!pClosedWindow) return; @@ -924,13 +1084,16 @@ void CWindowManager::fixWindowOnClose(CWindow* pClosedWindow) { return; } + // used by master layout + pClosedWindow->setDead(true); + + // FIX TREE ---- + // make the sibling replace the parent PSIBLING->setPosition(PPARENT->getPosition()); PSIBLING->setSize(PPARENT->getSize()); - - // make the sibling replace the parent PSIBLING->setParentNodeID(PPARENT->getParentNodeID()); - if (PPARENT->getParentNodeID() != 0 + if (PPARENT->getParentNodeID() != 0 && getWindowFromDrawable(PPARENT->getParentNodeID())) { if (getWindowFromDrawable(PPARENT->getParentNodeID())->getChildNodeAID() == PPARENT->getDrawable()) { getWindowFromDrawable(PPARENT->getParentNodeID())->setChildNodeAID(PSIBLING->getDrawable()); @@ -938,11 +1101,20 @@ void CWindowManager::fixWindowOnClose(CWindow* pClosedWindow) { getWindowFromDrawable(PPARENT->getParentNodeID())->setChildNodeBID(PSIBLING->getDrawable()); } } + // TREE FIXED ---- - // Make the sibling eat the closed window - PSIBLING->setDirtyRecursive(true); - PSIBLING->recalcSizePosRecursive(); + // Fix master stuff + const auto WORKSPACE = pClosedWindow->getWorkspaceID(); + fixMasterWorkspaceOnClosed(pClosedWindow); + // recalc the workspace + if (ConfigManager::getInt("layout") == LAYOUT_MASTER) + recalcEntireWorkspace(WORKSPACE); + else { + PSIBLING->recalcSizePosRecursive(); + PSIBLING->setDirtyRecursive(true); + } + // Remove the parent removeWindowFromVectorSafe(PPARENT->getDrawable()); @@ -1437,4 +1609,10 @@ void CWindowManager::refocusWindowOnClosed() { LastWindow = PWINDOW->getDrawable(); setFocusedWindow(PWINDOW->getDrawable()); +} + +void CWindowManager::recalcAllWorkspaces() { + for (auto& workspace : workspaces) { + recalcEntireWorkspace(workspace.getID()); + } } \ No newline at end of file diff --git a/src/windowManager.hpp b/src/windowManager.hpp index af5a38a..8973523 100644 --- a/src/windowManager.hpp +++ b/src/windowManager.hpp @@ -106,6 +106,10 @@ public: void updateActiveWindowName(); void updateBarInfo(); + int getWindowsOnWorkspace(const int&); + + void recalcAllWorkspaces(); + private: // Internal WM functions that don't have to be exposed @@ -122,6 +126,9 @@ public: xcb_visualtype_t* setupColors(const int&); void updateRootCursor(); void applyRoundedCornersToWindow(CWindow* pWindow); + SMonitor* getMonitorFromWorkspace(const int&); + void recalcEntireWorkspace(const int&); + void fixMasterWorkspaceOnClosed(CWindow* pWindow); }; inline std::unique_ptr g_pWindowManager = std::make_unique();