From b1c0f1cc018d13ac1e5ebccaade5528ec757bd74 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 29 Feb 2024 00:03:28 +0000 Subject: [PATCH] subsurface: Rewrite the subsurface tree (#4877) --- src/Compositor.hpp | 1 - src/Window.cpp | 4 + src/Window.hpp | 7 +- src/events/Events.hpp | 8 - src/events/Popups.cpp | 16 +- src/events/Windows.cpp | 17 +- src/helpers/Subsurface.cpp | 238 +++++++++++++++++++++++++ src/helpers/Subsurface.hpp | 51 ++++++ src/helpers/SubsurfaceTree.cpp | 312 --------------------------------- src/helpers/SubsurfaceTree.hpp | 60 ------- src/helpers/WLClasses.hpp | 12 +- 11 files changed, 312 insertions(+), 414 deletions(-) create mode 100644 src/helpers/Subsurface.cpp create mode 100644 src/helpers/Subsurface.hpp delete mode 100644 src/helpers/SubsurfaceTree.cpp delete mode 100644 src/helpers/SubsurfaceTree.hpp diff --git a/src/Compositor.hpp b/src/Compositor.hpp index c08a5931..491aee71 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -95,7 +95,6 @@ class CCompositor { std::vector> m_vWindows; std::vector> m_vXDGPopups; std::vector> m_vWorkspaces; - std::vector> m_vSubsurfaces; std::vector m_vWindowsFadingOut; std::vector m_vSurfacesFadingOut; diff --git a/src/Window.cpp b/src/Window.cpp index ece5b658..f1484cb0 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -471,6 +471,8 @@ void CWindow::onUnmap() { PMONITOR->solitaryClient = nullptr; g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID); + + m_pSubsurfaceHead.reset(); } void CWindow::onMap() { @@ -516,6 +518,8 @@ void CWindow::onMap() { m_bTearingHint = ctrl->pWlrHint->current; break; } + + m_pSubsurfaceHead = std::make_unique(this); } void CWindow::onBorderAngleAnimEnd(void* ptr) { diff --git a/src/Window.hpp b/src/Window.hpp index f8ba4180..2d7bc986 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -1,7 +1,7 @@ #pragma once #include "defines.hpp" -#include "helpers/SubsurfaceTree.hpp" +#include "helpers/Subsurface.hpp" #include "helpers/AnimatedVariable.hpp" #include "render/decorations/IHyprWindowDecoration.hpp" #include @@ -276,9 +276,10 @@ class CWindow { bool m_bWantsInitialFullscreen = false; // bitfield eSuppressEvents - uint64_t m_eSuppressedEvents = SUPPRESS_NONE; + uint64_t m_eSuppressedEvents = SUPPRESS_NONE; - SSurfaceTreeNode* m_pSurfaceTree = nullptr; + // for the subsurface tree + std::unique_ptr m_pSubsurfaceHead; // Animated border CGradientValueData m_cRealBorderColor = {0}; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 8b737f32..980142a0 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -22,14 +22,6 @@ namespace Events { DYNLISTENFUNC(unmapLayerSurface); DYNLISTENFUNC(commitLayerSurface); - // Subsurfaces - DYNLISTENFUNC(newSubsurfaceNode); - DYNLISTENFUNC(destroySubsurfaceNode); - DYNLISTENFUNC(mapSubsurface); - DYNLISTENFUNC(unmapSubsurface); - DYNLISTENFUNC(destroySubsurface); - DYNLISTENFUNC(commitSubsurface); - // Popups DYNLISTENFUNC(newPopup); // LayerSurface diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp index 41707b6a..ca1787f5 100644 --- a/src/events/Popups.cpp +++ b/src/events/Popups.cpp @@ -154,7 +154,7 @@ void Events::listener_mapPopupXDG(void* owner, void* data) { else if (PPOPUP->parentLS) PPOPUP->parentLS->popupSurfaces.emplace_back(PPOPUP->popup->base->surface); - PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow); + //PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow); int lx = 0, ly = 0; addPopupGlobalCoords(PPOPUP, &lx, &ly); @@ -170,7 +170,7 @@ void Events::listener_mapPopupXDG(void* owner, void* data) { g_pCompositor->setPreferredTransformForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->transform); } - Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree); + // Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree); } void Events::listener_repositionPopupXDG(void* owner, void* data) { @@ -204,7 +204,7 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) { if (PPOPUP->popup->base->surface == g_pCompositor->m_pLastFocus) g_pInputManager->releaseAllMouseButtons(); - SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree); + // SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree); int lx = 0, ly = 0; addPopupGlobalCoords(PPOPUP, &lx, &ly); @@ -220,7 +220,7 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) { else if (PPOPUP->parentLS) std::erase(PPOPUP->parentLS->popupSurfaces, PPOPUP->popup->base->surface); - PPOPUP->pSurfaceTree = nullptr; + // PPOPUP->pSurfaceTree = nullptr; g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface } @@ -260,10 +260,10 @@ void Events::listener_destroyPopupXDG(void* owner, void* data) { Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP); - if (PPOPUP->pSurfaceTree) { - SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree); - PPOPUP->pSurfaceTree = nullptr; - } + // if (PPOPUP->pSurfaceTree) { + // SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree); + // PPOPUP->pSurfaceTree = nullptr; + // } std::erase_if(g_pCompositor->m_vXDGPopups, [&](std::unique_ptr& el) { return el.get() == PPOPUP; }); } diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 6ea0bb0c..162415b4 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -486,8 +486,6 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_fDimPercent.setValueAndWarp(0); } - Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree); - if (!PWINDOW->m_bIsX11) { PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late"); @@ -538,8 +536,6 @@ void Events::listener_mapWindow(void* owner, void* data) { // recheck idle inhibitors g_pInputManager->recheckIdleInhibitorStatus(); - PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(PWINDOW->m_pWLSurface.wlr(), addViewCoords, PWINDOW, PWINDOW); - PWINDOW->updateToplevel(); if (workspaceSilent) { @@ -757,11 +753,6 @@ void Events::listener_unmapWindow(void* owner, void* data) { Debug::log(LOG, "Unmapped was not focused, ignoring a refocus."); } - Debug::log(LOG, "Destroying the SubSurface tree of unmapped window {}", PWINDOW); - SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree); - - PWINDOW->m_pSurfaceTree = nullptr; - PWINDOW->m_bFadingOut = true; g_pCompositor->addToFadingOutSafe(PWINDOW); @@ -842,6 +833,8 @@ void Events::listener_commitWindow(void* owner, void* data) { g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); + PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces(); + if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) return; @@ -895,12 +888,6 @@ void Events::listener_destroyWindow(void* owner, void* data) { g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); - if (PWINDOW->m_pSurfaceTree) { - Debug::log(LOG, "Destroying Subsurface tree of {} in destroyWindow", PWINDOW); - SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree); - PWINDOW->m_pSurfaceTree = nullptr; - } - PWINDOW->m_bReadyToDelete = true; if (!PWINDOW->m_bFadingOut) { diff --git a/src/helpers/Subsurface.cpp b/src/helpers/Subsurface.cpp new file mode 100644 index 00000000..0923e9cc --- /dev/null +++ b/src/helpers/Subsurface.cpp @@ -0,0 +1,238 @@ +#include "Subsurface.hpp" +#include "../events/Events.hpp" +#include "../Compositor.hpp" + +static void onNewSubsurface(void* owner, void* data); + +CSubsurface::CSubsurface(CWindow* pOwner) : m_pWindowParent(pOwner) { + initSignals(); + + wlr_subsurface* wlrSubsurface; + wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_below, current.link) { + ::onNewSubsurface(this, wlrSubsurface); + } + wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_above, current.link) { + ::onNewSubsurface(this, wlrSubsurface); + } +} + +CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { + m_sWLSurface.assign(pSubsurface->surface); + initSignals(); + initExistingSubsurfaces(); +} + +CSubsurface::~CSubsurface() { + hyprListener_newSubsurface.removeCallback(); + + if (!m_pSubsurface) + return; + + hyprListener_commitSubsurface.removeCallback(); + hyprListener_destroySubsurface.removeCallback(); + + const auto COORDS = coordsGlobal(); + + CBox box = {COORDS, m_vLastSize}; + g_pHyprRenderer->damageBox(&box); +} + +static void onNewSubsurface(void* owner, void* data) { + const auto PSUBSURFACE = (CSubsurface*)owner; + PSUBSURFACE->onNewSubsurface((wlr_subsurface*)data); +} + +static void onDestroySubsurface(void* owner, void* data) { + const auto PSUBSURFACE = (CSubsurface*)owner; + PSUBSURFACE->onDestroy(); +} + +static void onCommitSubsurface(void* owner, void* data) { + const auto PSUBSURFACE = (CSubsurface*)owner; + PSUBSURFACE->onCommit(); +} + +static void onMapSubsurface(void* owner, void* data) { + const auto PSUBSURFACE = (CSubsurface*)owner; + PSUBSURFACE->onMap(); +} + +static void onUnmapSubsurface(void* owner, void* data) { + const auto PSUBSURFACE = (CSubsurface*)owner; + PSUBSURFACE->onUnmap(); +} + +void CSubsurface::initSignals() { + if (m_pSubsurface) { + hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface"); + hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface"); + hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface"); + hyprListener_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface"); + hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface"); + } else { + if (m_pWindowParent) + hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface"); + else + RASSERT(false, "CSubsurface::initSignals empty subsurface"); + } +} + +void CSubsurface::checkSiblingDamage() { + if (!m_pParent) + return; // ?????????? + + const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0; + + for (auto& n : m_pParent->m_vChildren) { + if (n.get() == this) + continue; + + const auto COORDS = n->coordsGlobal(); + g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE); + } +} + +void CSubsurface::recheckDamageForSubsurfaces() { + const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0; + + for (auto& n : m_vChildren) { + const auto COORDS = n->coordsGlobal(); + g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE); + } +} + +void CSubsurface::onCommit() { + // no damaging if it's not visible + if (!g_pHyprRenderer->shouldRenderWindow(m_pWindowParent)) { + m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + + static auto* const PLOGDAMAGE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("debug:log_damage"); + if (**PLOGDAMAGE) + Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowParent); + return; + } + + const auto COORDS = coordsGlobal(); + + const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0; + + g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE); + + // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) + checkSiblingDamage(); + + if (m_vLastSize != Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}) { + CBox box{COORDS, m_vLastSize}; + g_pHyprRenderer->damageBox(&box); + m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + box = {COORDS, m_vLastSize}; + g_pHyprRenderer->damageBox(&box); + } + + if (m_pWindowParent) { + if (m_pWindowParent->m_bIsX11) + m_pWindowParent->m_vReportedSize = m_pWindowParent->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. + + // tearing: if solitary, redraw it. This still might be a single surface window + const auto PMONITOR = g_pCompositor->getMonitorFromID(m_pWindowParent->m_iMonitorID); + if (PMONITOR && PMONITOR->solitaryClient == m_pWindowParent && m_pWindowParent->canBeTorn() && PMONITOR->tearingState.canTear && + m_sWLSurface.wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) { + CRegion damageBox{&m_sWLSurface.wlr()->buffer_damage}; + + if (!damageBox.empty()) { + if (PMONITOR->tearingState.busy) { + PMONITOR->tearingState.frameScheduledWhileBusy = true; + } else { + PMONITOR->tearingState.nextRenderTorn = true; + g_pHyprRenderer->renderMonitor(PMONITOR); + } + } + } + } +} + +void CSubsurface::onDestroy() { + // destroy children + m_vChildren.clear(); + + if (!m_pSubsurface) + return; // dummy node, nothing to do, it's the parent dying + + // kill ourselves + std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; }); +} + +void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) { + CSubsurface* PSUBSURFACE = nullptr; + + if (m_pWindowParent) + PSUBSURFACE = m_vChildren.emplace_back(std::make_unique(pSubsurface, m_pWindowParent)).get(); + PSUBSURFACE->m_pParent = this; + + ASSERT(PSUBSURFACE); +} + +void CSubsurface::onMap() { + m_vLastSize = {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + + const auto COORDS = coordsGlobal(); + CBox box{COORDS, m_vLastSize}; + g_pHyprRenderer->damageBox(&box); + + if (m_pWindowParent) + m_pWindowParent->updateSurfaceScaleTransformDetails(); +} + +void CSubsurface::onUnmap() { + const auto COORDS = coordsGlobal(); + CBox box{COORDS, m_vLastSize}; + g_pHyprRenderer->damageBox(&box); + + if (m_sWLSurface.wlr() == g_pCompositor->m_pLastFocus) + g_pInputManager->releaseAllMouseButtons(); + + if (m_pWindowParent) + m_pWindowParent->updateSurfaceScaleTransformDetails(); + + g_pInputManager->simulateMouseMovement(); + + // TODO: should this remove children? Currently it won't, only on .destroy +} + +Vector2D CSubsurface::coordsRelativeToParent() { + Vector2D offset; + + CSubsurface* current = this; + + while (current->m_pParent) { + + offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy}; + offset += {current->m_pSubsurface->current.x, current->m_pSubsurface->current.y}; + + current = current->m_pParent; + } + + return offset; +} + +Vector2D CSubsurface::coordsGlobal() { + Vector2D coords = coordsRelativeToParent(); + + if (m_pWindowParent) + coords += m_pWindowParent->m_vRealPosition.vec(); + + return coords; +} + +void CSubsurface::initExistingSubsurfaces() { + if (m_pWindowParent) + return; + + wlr_subsurface* wlrSubsurface; + wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_below, current.link) { + ::onNewSubsurface(this, wlrSubsurface); + } + wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_above, current.link) { + ::onNewSubsurface(this, wlrSubsurface); + } +} \ No newline at end of file diff --git a/src/helpers/Subsurface.hpp b/src/helpers/Subsurface.hpp new file mode 100644 index 00000000..a8f028af --- /dev/null +++ b/src/helpers/Subsurface.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "../defines.hpp" +#include +#include "WLSurface.hpp" + +class CWindow; + +class CSubsurface { + public: + // root dummy nodes + CSubsurface(CWindow* pOwner); + + // real nodes + CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner); + + ~CSubsurface(); + + Vector2D coordsRelativeToParent(); + Vector2D coordsGlobal(); + + void onCommit(); + void onDestroy(); + void onNewSubsurface(wlr_subsurface* pSubsurface); + void onMap(); + void onUnmap(); + + void recheckDamageForSubsurfaces(); + + private: + DYNLISTENER(destroySubsurface); + DYNLISTENER(commitSubsurface); + DYNLISTENER(newSubsurface); + DYNLISTENER(mapSubsurface); + DYNLISTENER(unmapSubsurface); + + wlr_subsurface* m_pSubsurface = nullptr; + CWLSurface m_sWLSurface; + Vector2D m_vLastSize = {}; + + // if nullptr, means it's a dummy node + CSubsurface* m_pParent = nullptr; + + CWindow* m_pWindowParent = nullptr; + + std::vector> m_vChildren; + + void initSignals(); + void initExistingSubsurfaces(); + void checkSiblingDamage(); +}; \ No newline at end of file diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp deleted file mode 100644 index b4ea6d85..00000000 --- a/src/helpers/SubsurfaceTree.cpp +++ /dev/null @@ -1,312 +0,0 @@ -#include "SubsurfaceTree.hpp" -#include "../events/Events.hpp" -#include "../Compositor.hpp" - -void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) { - if (!node->pSurface || !node->pSurface->exists()) - return; - - *lx += node->pSurface->wlr()->current.dx; - *ly += node->pSurface->wlr()->current.dy; - - if (node->offsetfn) { - // This is the root node - RASSERT(!node->pSubsurface, "Node had no subsurface!"); - node->offsetfn(node->globalOffsetData, lx, ly); - } else { - RASSERT(node->pSubsurface, "Node had no subsurface!"); - - *lx += node->pSubsurface->pSubsurface->current.x; - *ly += node->pSubsurface->pSubsurface->current.y; - - addSurfaceGlobalOffset(node->pParent, lx, ly); - } -} - -SSurfaceTreeNode* createTree(wlr_surface* pSurface, CWindow* pWindow) { - const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.emplace_back(); - - if (pSurface->data) - PNODE->pSurface = (CWLSurface*)pSurface->data; - else { - PNODE->pInternalSurface = pSurface; - PNODE->pSurface = &PNODE->pInternalSurface; - } - - PNODE->pWindowOwner = pWindow; - - PNODE->hyprListener_newSubsurface.initCallback(&pSurface->events.new_subsurface, &Events::listener_newSubsurfaceNode, PNODE, "SurfaceTreeNode"); - PNODE->hyprListener_commit.initCallback(&pSurface->events.commit, &Events::listener_commitSubsurface, PNODE, "SurfaceTreeNode"); - PNODE->hyprListener_destroy.initCallback(&pSurface->events.destroy, &Events::listener_destroySubsurfaceNode, PNODE, "SurfaceTreeNode"); - - wlr_subsurface* wlrSubsurface; - wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) { - Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface); - } - wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) { - Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface); - } - - return PNODE; -} - -SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface, CWindow* pWindow) { - const auto PNODE = createTree(surface, pWindow); - PNODE->pParent = pParent; - PNODE->pSubsurface = pSubsurface; - - Debug::log(LOG, "Creating a subsurface Node! {}", pWindow); - - return PNODE; -} - -SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data, CWindow* pWindow) { - const auto PNODE = createTree(pSurface, pWindow); - - Debug::log(LOG, "Creating a surfaceTree Root! {}", pWindow); - - PNODE->offsetfn = fn; - PNODE->globalOffsetData = data; - - return PNODE; -} - -void destroySubsurface(SSubsurface* pSubsurface); - -void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) { - bool exists = false; - for (auto& n : surfaceTreeNodes) { - if (&n == pNode) { - exists = true; - break; - } - } - - if (!exists) { - Debug::log(ERR, "Tried to remove a SurfaceTreeNode that doesn't exist?? (Node {:x})", (uintptr_t)pNode); - return; - } - - for (auto& c : pNode->childSubsurfaces) - destroySubsurface(&c); - - pNode->childSubsurfaces.clear(); - - pNode->hyprListener_commit.removeCallback(); - pNode->hyprListener_destroy.removeCallback(); - pNode->hyprListener_newSubsurface.removeCallback(); - - // damage - if (pNode->pSurface && pNode->pSurface->exists()) { - CBox extents = {}; - wlr_surface_get_extends(pNode->pSurface->wlr(), extents.pWlr()); - extents.applyFromWlr(); - - int lx = 0, ly = 0; - addSurfaceGlobalOffset(pNode, &lx, &ly); - - extents.x += lx; - extents.y += ly; - - g_pHyprRenderer->damageBox(&extents); - } - - // remove references to this node - for (auto& tn : surfaceTreeNodes) { - for (auto& cs : tn.childSubsurfaces) { - if (cs.pChild == pNode) - cs.pChild = nullptr; - } - } - - surfaceTreeNodes.remove(*pNode); - - Debug::log(LOG, "SurfaceTree Node removed"); -} - -void destroySubsurface(SSubsurface* pSubsurface) { - if (pSubsurface->pChild) { - SubsurfaceTree::destroySurfaceTree(pSubsurface->pChild); - pSubsurface->pChild = nullptr; - } - - pSubsurface->hyprListener_destroy.removeCallback(); - pSubsurface->hyprListener_map.removeCallback(); - pSubsurface->hyprListener_unmap.removeCallback(); -} - -// -// Subsurface listeners -// - -void Events::listener_newSubsurfaceNode(void* owner, void* data) { - SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner; - - const auto PSUBSURFACE = (wlr_subsurface*)data; - - const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.emplace_back(); - - Debug::log(LOG, "Added a new subsurface {:x}", (uintptr_t)PSUBSURFACE); - - PNEWSUBSURFACE->pSubsurface = PSUBSURFACE; - PNEWSUBSURFACE->pParent = pNode; - - PNEWSUBSURFACE->hyprListener_map.initCallback(&PSUBSURFACE->surface->events.map, &Events::listener_mapSubsurface, PNEWSUBSURFACE, "Subsurface"); - PNEWSUBSURFACE->hyprListener_unmap.initCallback(&PSUBSURFACE->surface->events.unmap, &Events::listener_unmapSubsurface, PNEWSUBSURFACE, "Subsurface"); - PNEWSUBSURFACE->hyprListener_destroy.initCallback(&PSUBSURFACE->events.destroy, &Events::listener_destroySubsurface, PNEWSUBSURFACE, "Subsurface"); - - PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner; - - if (PSUBSURFACE->surface->mapped) - listener_mapSubsurface(PNEWSUBSURFACE, nullptr); - - wlr_subsurface* existingWlrSubsurface; - wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) { - listener_newSubsurfaceNode(pNode, existingWlrSubsurface); - } - wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_above, current.link) { - listener_newSubsurfaceNode(pNode, existingWlrSubsurface); - } -} - -void Events::listener_mapSubsurface(void* owner, void* data) { - SSubsurface* subsurface = (SSubsurface*)owner; - - if (subsurface->pChild) - return; - - Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface); - - subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner); - - if (subsurface->pWindowOwner) - subsurface->pWindowOwner->updateSurfaceScaleTransformDetails(); -} - -void Events::listener_unmapSubsurface(void* owner, void* data) { - SSubsurface* subsurface = (SSubsurface*)owner; - - Debug::log(LOG, "Subsurface {:x} unmapped", (uintptr_t)subsurface); - - if (subsurface->pSubsurface->surface == g_pCompositor->m_pLastFocus) - g_pInputManager->releaseAllMouseButtons(); - - if (subsurface->pChild) { - const auto PNODE = subsurface->pChild; - - const auto IT = - std::find_if(SubsurfaceTree::surfaceTreeNodes.begin(), SubsurfaceTree::surfaceTreeNodes.end(), [&](const SSurfaceTreeNode& other) { return &other == PNODE; }); - - if (IT != SubsurfaceTree::surfaceTreeNodes.end()) { - if (PNODE->pSurface && PNODE->pSurface->exists()) { - int lx = 0, ly = 0; - addSurfaceGlobalOffset(PNODE, &lx, &ly); - - CBox extents = {lx, ly, 0, 0}; - - extents.width = PNODE->pSurface->wlr()->current.width; - extents.height = PNODE->pSurface->wlr()->current.height; - - g_pHyprRenderer->damageBox(&extents); - } - - // SubsurfaceTree::destroySurfaceTree(subsurface->pChild); - // subsurface->pChild = nullptr; - } - } - - g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface -} - -void Events::listener_commitSubsurface(void* owner, void* data) { - SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner; - - // no damaging if it's not visible - if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) { - pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{}; - - static auto* const PLOGDAMAGE = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("debug:log_damage"); - if (**PLOGDAMAGE) - Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner); - return; - } - - int lx = 0, ly = 0; - - addSurfaceGlobalOffset(pNode, &lx, &ly); - - const double SCALE = pNode->pWindowOwner && pNode->pWindowOwner->m_bIsX11 ? 1.0 / pNode->pWindowOwner->m_fX11SurfaceScaledBy : 1.0; - - // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) - // What this does is that basically, if the pNode is a child of some other node, on commit, - // it will also damage (check & damage if needed) all its siblings. - if (pNode->pParent) - for (auto& cs : pNode->pParent->childSubsurfaces) { - const auto NODECOORDS = pNode->pSubsurface ? Vector2D(pNode->pSubsurface->pSubsurface->current.x, pNode->pSubsurface->pSubsurface->current.y) : Vector2D(); - - if (&cs != pNode->pSubsurface && cs.pSubsurface) { - g_pHyprRenderer->damageSurface(cs.pSubsurface->surface, lx - NODECOORDS.x + cs.pSubsurface->current.x, ly - NODECOORDS.y + cs.pSubsurface->current.y, SCALE); - } - } - - if (pNode->pSurface && pNode->pSurface->exists()) { - g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE); - - if (pNode->lastSize != Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} && pNode->pWindowOwner) - g_pHyprRenderer->damageWindow(pNode->pWindowOwner); - } - - if (pNode->pWindowOwner) { - if (pNode->pWindowOwner->m_bIsX11) - pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. - - // tearing: if solitary, redraw it. This still might be a single surface window - const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID); - if (PMONITOR && PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear && - pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) { - CRegion damageBox{&pNode->pSurface->wlr()->buffer_damage}; - - if (!damageBox.empty()) { - if (PMONITOR->tearingState.busy) { - PMONITOR->tearingState.frameScheduledWhileBusy = true; - } else { - PMONITOR->tearingState.nextRenderTorn = true; - g_pHyprRenderer->renderMonitor(PMONITOR); - } - } - } - } - - pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{}; -} - -void Events::listener_destroySubsurface(void* owner, void* data) { - SSubsurface* subsurface = (SSubsurface*)owner; - - if (subsurface->pChild) { - SubsurfaceTree::destroySurfaceTree(subsurface->pChild); - } - - Debug::log(LOG, "Subsurface {:x} destroyed", (uintptr_t)subsurface); - - subsurface->hyprListener_destroy.removeCallback(); - subsurface->hyprListener_map.removeCallback(); - subsurface->hyprListener_unmap.removeCallback(); - - subsurface->pParent->childSubsurfaces.remove(*subsurface); -} - -void Events::listener_destroySubsurfaceNode(void* owner, void* data) { - SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner; - - Debug::log(LOG, "Subsurface Node {:x} destroyed", (uintptr_t)pNode); - - for (auto& c : pNode->childSubsurfaces) - destroySubsurface(&c); - - pNode->hyprListener_commit.removeCallback(); - pNode->hyprListener_newSubsurface.removeCallback(); - pNode->hyprListener_destroy.removeCallback(); - - SubsurfaceTree::surfaceTreeNodes.remove(*pNode); -} diff --git a/src/helpers/SubsurfaceTree.hpp b/src/helpers/SubsurfaceTree.hpp deleted file mode 100644 index 7a8b8fb8..00000000 --- a/src/helpers/SubsurfaceTree.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "../defines.hpp" -#include -#include "WLSurface.hpp" - -struct SSubsurface; -class CWindow; - -typedef void (*applyGlobalOffsetFn)(void*, int*, int*); - -struct SSurfaceTreeNode { - CWLSurface* pSurface = nullptr; // actual surface - CWLSurface pInternalSurface; // not present for head nodes to not dupe wlr_surface ownership - - DYNLISTENER(newSubsurface); - DYNLISTENER(commit); - DYNLISTENER(destroy); - - SSurfaceTreeNode* pParent = nullptr; - SSubsurface* pSubsurface = nullptr; - - std::list childSubsurfaces; - - applyGlobalOffsetFn offsetfn; - void* globalOffsetData; - CWindow* pWindowOwner = nullptr; - - Vector2D lastSize; - - // - bool operator==(const SSurfaceTreeNode& rhs) const { - return pSurface == rhs.pSurface; - } -}; - -struct SSubsurface { - wlr_subsurface* pSubsurface = nullptr; - - SSurfaceTreeNode* pParent = nullptr; - SSurfaceTreeNode* pChild = nullptr; - - DYNLISTENER(map); - DYNLISTENER(unmap); - DYNLISTENER(destroy); - - CWindow* pWindowOwner = nullptr; - - // - bool operator==(const SSubsurface& rhs) const { - return pSubsurface == rhs.pSubsurface; - } -}; - -namespace SubsurfaceTree { - SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*, CWindow* pWindow = nullptr); - void destroySurfaceTree(SSurfaceTreeNode*); - - inline std::list surfaceTreeNodes; -}; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index b62a6489..c1110eaa 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -4,7 +4,7 @@ #include "../defines.hpp" #include "wlr-layer-shell-unstable-v1-protocol.h" #include "../Window.hpp" -#include "SubsurfaceTree.hpp" +#include "Subsurface.hpp" #include "AnimatedVariable.hpp" #include "WLSurface.hpp" #include "Region.hpp" @@ -213,13 +213,11 @@ struct SXDGPopup { DYNLISTENER(commitPopupXDG); DYNLISTENER(repositionPopupXDG); - double lx; - double ly; + double lx; + double ly; - Vector2D lastPos = {}; - bool repositionRequested = false; - - SSurfaceTreeNode* pSurfaceTree = nullptr; + Vector2D lastPos = {}; + bool repositionRequested = false; // For the list lookup bool operator==(const SXDGPopup& rhs) const {