diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 6386a07d..c0059836 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -109,6 +109,9 @@ void CCompositor::startCompositor() { Debug::log(LOG, "Creating the XWaylandManager!"); g_pXWaylandManager = std::make_unique(); + + Debug::log(LOG, "Creating the LayoutManager!"); + g_pLayoutManager = std::make_unique(); // // @@ -185,7 +188,7 @@ bool CCompositor::windowExists(CWindow* pWindow) { CWindow* CCompositor::vectorToWindow(const Vector2D& pos) { for (auto& w : m_lWindows) { - wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y}; + wlr_box box = {w.m_vRealPosition.x, w.m_vRealPosition.y, w.m_vRealSize.x, w.m_vRealSize.y}; if (wlr_box_contains_point(&box, pos.x, pos.y)) return &w; } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 26b16f42..7fd26b38 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -11,10 +11,10 @@ #include "managers/ThreadManager.hpp" #include "managers/XWaylandManager.hpp" #include "managers/InputManager.hpp" +#include "managers/LayoutManager.hpp" #include "helpers/Monitor.hpp" #include "Window.hpp" #include "render/Renderer.hpp" - class CCompositor { public: CCompositor(); diff --git a/src/defines.hpp b/src/defines.hpp index 94807ac1..9c3856aa 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -11,4 +11,8 @@ #define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name }; #define DYNLISTENER(name) wl_listener listen_##name = { .notify = Events::listener_##name }; -#define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2)) \ No newline at end of file +#define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2)) + +#define interface class + +#define STICKS(a, b) abs((a) - (b)) < 2 \ No newline at end of file diff --git a/src/events/Events.cpp b/src/events/Events.cpp index 24c51a07..6baaeebb 100644 --- a/src/events/Events.cpp +++ b/src/events/Events.cpp @@ -206,10 +206,8 @@ void Events::listener_mapWindow(wl_listener* listener, void* data) { PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_bMappedX11 = true; - // test - PWINDOW->m_vSize = PMONITOR->vecSize; - PWINDOW->m_vPosition = PMONITOR->vecPosition; - g_pXWaylandManager->setWindowSize(PWINDOW, PMONITOR->vecSize); + g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); + g_pCompositor->focusWindow(PWINDOW); Debug::log(LOG, "Map request dispatched."); @@ -218,6 +216,8 @@ void Events::listener_mapWindow(wl_listener* listener, void* data) { void Events::listener_unmapWindow(wl_listener* listener, void* data) { CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_unmapWindow); + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); + g_pCompositor->removeWindowFromVectorSafe(PWINDOW); Debug::log(LOG, "Window %x unmapped", PWINDOW); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp new file mode 100644 index 00000000..290a8a6a --- /dev/null +++ b/src/layout/DwindleLayout.cpp @@ -0,0 +1,202 @@ +#include "DwindleLayout.hpp" +#include "../Compositor.hpp" + +int CHyprDwindleLayout::getNodesOnMonitor(const int& id) { + int no = 0; + for (auto& n : m_lDwindleNodesData) { + if (n.monitorID == id) + ++no; + } + return no; +} + +SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnMonitor(const int& id) { + for (auto& n : m_lDwindleNodesData) { + if (n.monitorID == id) + return &n; + } + return nullptr; +} + +SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(CWindow* pWindow) { + for (auto& n : m_lDwindleNodesData) { + if (n.pWindow == pWindow) + return &n; + } + + return nullptr; +} + +void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->monitorID); + + if (!PMONITOR){ + Debug::log(ERR, "Orphaned Node %x (monitor ID: %i)!!", pNode, pNode->monitorID); + return; + } + + // Don't set nodes, only windows. + if (pNode->isNode) + 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; + + PWINDOW->m_vEffectivePosition = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE); + PWINDOW->m_vEffectiveSize = 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); + + PWINDOW->m_vEffectivePosition = PWINDOW->m_vEffectivePosition + OFFSETTOPLEFT; + PWINDOW->m_vEffectiveSize = PWINDOW->m_vEffectiveSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT; + + // TEMP: remove when anims added + PWINDOW->m_vRealPosition = PWINDOW->m_vEffectivePosition; + PWINDOW->m_vRealSize = PWINDOW->m_vEffectiveSize; + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize); +} + +void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) { + m_lDwindleNodesData.push_back(SDwindleNodeData()); + const auto PNODE = &m_lDwindleNodesData.back(); + + if (pWindow->m_bIsFloating) { + // handle floating, TODO: + return; + } + + // Populate the node with our window's data + PNODE->monitorID = pWindow->m_iMonitorID; + PNODE->pWindow = pWindow; + PNODE->isNode = false; + + const auto PMONITOR = g_pCompositor->getMonitorFromID(PNODE->monitorID); + + // if it's the first, it's easy. Make it fullscreen. + if (getNodesOnMonitor(pWindow->m_iMonitorID) == 1) { + PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; + PNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight; + + applyNodeDataToWindow(PNODE); + + return; + } + + // If it's not, get the last node. + const auto PLASTFOCUS = getNodeFromWindow(g_pCompositor->m_pLastFocus); + SDwindleNodeData* OPENINGON = PLASTFOCUS; + if (PLASTFOCUS) { + if (PLASTFOCUS->monitorID != PNODE->monitorID) { + OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindow(g_pInputManager->getMouseCoordsInternal())); + } + } else { + OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindow(g_pInputManager->getMouseCoordsInternal())); + } + + if (!OPENINGON) { + OPENINGON = getFirstNodeOnMonitor(PNODE->monitorID); + } + + if (!OPENINGON) { + Debug::log(ERR, "OPENINGON still null?????"); + return; + } + + m_lDwindleNodesData.push_back(SDwindleNodeData()); + const auto NEWPARENT = &m_lDwindleNodesData.back(); + + // make the parent have the OPENINGON's stats + NEWPARENT->children[0] = OPENINGON; + NEWPARENT->children[1] = PNODE; + NEWPARENT->position = OPENINGON->position; + NEWPARENT->size = OPENINGON->size; + NEWPARENT->monitorID = OPENINGON->monitorID; + NEWPARENT->isNode = true; // it is a node + + // and update the previous parent if it exists + if (OPENINGON->pParent) { + if (OPENINGON->pParent->children[0] == OPENINGON) { + OPENINGON->pParent->children[0] == NEWPARENT; + } else { + OPENINGON->pParent->children[1] == NEWPARENT; + } + } + + // Update the children + if (NEWPARENT->size.x > NEWPARENT->size.y) { + // split sidey + OPENINGON->position = NEWPARENT->position; + OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y); + PNODE->position = Vector2D(NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y); + PNODE->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y); + } else { + // split toppy bottomy + OPENINGON->position = NEWPARENT->position; + OPENINGON->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f); + PNODE->position = Vector2D(NEWPARENT->position.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f); + PNODE->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f); + } + + OPENINGON->pParent = NEWPARENT; + PNODE->pParent = NEWPARENT; + + applyNodeDataToWindow(PNODE); + applyNodeDataToWindow(OPENINGON); +} + +void CHyprDwindleLayout::onWindowRemoved(CWindow* pWindow) { + if (!g_pCompositor->windowValidMapped(pWindow)) + return; + + const auto PNODE = getNodeFromWindow(pWindow); + + if (!PNODE) + return; + + const auto PPARENT = PNODE->pParent; + + if (!PPARENT){ + m_lDwindleNodesData.remove(*PNODE); + return; + } + + const auto PSIBLING = PPARENT->children[0] == PNODE ? PPARENT->children[1] : PPARENT->children[0]; + + PSIBLING->position = PPARENT->position; + PSIBLING->size = PPARENT->size; + PSIBLING->pParent = PPARENT->pParent; + + if (PPARENT->pParent != nullptr) { + if (PPARENT->pParent->children[0] == PPARENT) { + PPARENT->pParent->children[0] = PSIBLING; + } else { + PPARENT->pParent->children[1] = PSIBLING; + } + } + + m_lDwindleNodesData.remove(*PPARENT); + m_lDwindleNodesData.remove(*PNODE); + + applyNodeDataToWindow(PSIBLING); +} \ No newline at end of file diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp new file mode 100644 index 00000000..b666d72a --- /dev/null +++ b/src/layout/DwindleLayout.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "IHyprLayout.hpp" +#include + +struct SDwindleNodeData { + SDwindleNodeData* pParent = nullptr; + bool isNode = false; + + CWindow* pWindow = nullptr; + + std::array children = { nullptr, nullptr }; + + Vector2D position; + Vector2D size; + + int monitorID = -1; + + // For list lookup + bool operator==(const SDwindleNodeData& rhs) { + return pWindow == rhs.pWindow && monitorID == rhs.monitorID && position == rhs.position && size == rhs.size && pParent == rhs.pParent; + } + + // TODO: recalcsizepos for dynamic +}; + +class CHyprDwindleLayout : public IHyprLayout { +public: + virtual void onWindowCreated(CWindow*); + virtual void onWindowRemoved(CWindow*); + +private: + + std::list m_lDwindleNodesData; + + int getNodesOnMonitor(const int&); + void applyNodeDataToWindow(SDwindleNodeData*); + SDwindleNodeData* getNodeFromWindow(CWindow*); + SDwindleNodeData* getFirstNodeOnMonitor(const int&); +}; \ No newline at end of file diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp new file mode 100644 index 00000000..feaaa835 --- /dev/null +++ b/src/layout/IHyprLayout.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "../defines.hpp" +#include "../Window.hpp" + +interface IHyprLayout { +public: + + virtual void onWindowCreated(CWindow*) = 0; + virtual void onWindowRemoved(CWindow*) = 0; + +}; \ No newline at end of file diff --git a/src/managers/InputManager.cpp b/src/managers/InputManager.cpp index 725ce672..492251fd 100644 --- a/src/managers/InputManager.cpp +++ b/src/managers/InputManager.cpp @@ -45,7 +45,7 @@ void CInputManager::mouseMoveUnified(uint32_t time) { g_pCompositor->focusWindow(PWINDOW); - Vector2D surfaceLocal = m_vWLRMouseCoords - PWINDOW->m_vPosition; + Vector2D surfaceLocal = m_vWLRMouseCoords - PWINDOW->m_vEffectivePosition; wlr_seat_pointer_notify_enter(g_pCompositor->m_sWLRSeat, g_pXWaylandManager->getWindowSurface(PWINDOW), surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sWLRSeat, time, surfaceLocal.x, surfaceLocal.y); diff --git a/src/managers/LayoutManager.cpp b/src/managers/LayoutManager.cpp new file mode 100644 index 00000000..ec723350 --- /dev/null +++ b/src/managers/LayoutManager.cpp @@ -0,0 +1,11 @@ +#include "LayoutManager.hpp" + +IHyprLayout* CLayoutManager::getCurrentLayout() { + switch (m_iCurrentLayoutID) { + case DWINDLE: + return &m_cDwindleLayout; + } + + // fallback + return &m_cDwindleLayout; +} \ No newline at end of file diff --git a/src/managers/LayoutManager.hpp b/src/managers/LayoutManager.hpp new file mode 100644 index 00000000..20f1f7f9 --- /dev/null +++ b/src/managers/LayoutManager.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "../layout/DwindleLayout.hpp" + +class CLayoutManager { +public: + + IHyprLayout* getCurrentLayout(); + +private: + enum HYPRLAYOUTS { + DWINDLE = 0, + }; + + HYPRLAYOUTS m_iCurrentLayoutID = DWINDLE; + + CHyprDwindleLayout m_cDwindleLayout; +}; + +inline std::unique_ptr g_pLayoutManager; \ No newline at end of file diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 1c28ec35..dfe6cb19 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -64,8 +64,8 @@ void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) { } void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size) { - if (pWindow->m_bIsX11) - wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pWindow->m_vPosition.x, pWindow->m_vPosition.y, size.x, size.y); + if (pWindow->m_bIsX11) + wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pWindow->m_vEffectivePosition.x, pWindow->m_vEffectivePosition.y, size.x, size.y); else wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b335cbe0..aeb19008 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -53,15 +53,15 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { if (w.m_bIsX11) continue; - wlr_box geometry = { w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y }; + wlr_box geometry = { w.m_vRealPosition.x, w.m_vRealPosition.y, w.m_vRealSize.x, w.m_vRealSize.y }; if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, PMONITOR->output, &geometry)) continue; // render the bad boy - wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, PMONITOR->output, &w.m_vPosition.x, &w.m_vPosition.y); + wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, PMONITOR->output, &w.m_vRealPosition.x, &w.m_vRealPosition.y); - SRenderData renderdata = {PMONITOR->output, time, w.m_vPosition.x, w.m_vPosition.y}; + SRenderData renderdata = {PMONITOR->output, time, w.m_vRealPosition.x, w.m_vRealPosition.y}; wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(&w), renderSurface, &renderdata); wlr_xdg_surface_for_each_popup_surface(w.m_uSurface.xdg, renderSurface, &renderdata); @@ -75,15 +75,15 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { if (!g_pCompositor->windowValidMapped(&w)) continue; - wlr_box geometry = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y}; + wlr_box geometry = {w.m_vRealPosition.x, w.m_vRealPosition.y, w.m_vRealSize.x, w.m_vRealSize.y}; if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, PMONITOR->output, &geometry)) continue; // render the bad boy - wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, PMONITOR->output, &w.m_vPosition.x, &w.m_vPosition.y); + wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, PMONITOR->output, &w.m_vRealPosition.x, &w.m_vRealPosition.y); - SRenderData renderdata = {PMONITOR->output, time, w.m_vPosition.x, w.m_vPosition.y}; + SRenderData renderdata = {PMONITOR->output, time, w.m_vRealPosition.x, w.m_vRealPosition.y}; if (w.m_uSurface.xwayland->surface) wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(&w), renderSurface, &renderdata);