From ad36a9dc9ed032e6e34c06f78995bca0045f85b0 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Sun, 27 Mar 2022 17:25:20 +0200 Subject: rework popups completely --- src/helpers/SubsurfaceTree.cpp | 163 +++++++++++++++++++++++++++++++++++++++++ src/helpers/SubsurfaceTree.hpp | 50 +++++++++++++ src/helpers/WLClasses.hpp | 43 ++--------- 3 files changed, 221 insertions(+), 35 deletions(-) create mode 100644 src/helpers/SubsurfaceTree.cpp create mode 100644 src/helpers/SubsurfaceTree.hpp (limited to 'src/helpers') diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp new file mode 100644 index 00000000..cdadbe75 --- /dev/null +++ b/src/helpers/SubsurfaceTree.cpp @@ -0,0 +1,163 @@ +#include "SubsurfaceTree.hpp" +#include "../events/Events.hpp" + +void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) { + *lx += node->pSurface->sx; + *ly += node->pSurface->sy; + + 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) { + SubsurfaceTree::surfaceTreeNodes.push_back(SSurfaceTreeNode()); + + const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.back(); + + PNODE->pSurface = pSurface; + + PNODE->listen_newSubsurface.notify = Events::listener_newSubsurfaceNode; + PNODE->listen_commit.notify = Events::listener_commitSubsurface; + PNODE->listen_destroy.notify = Events::listener_destroySubsurfaceNode; + + wl_signal_add(&pSurface->events.commit, &PNODE->listen_commit); + wl_signal_add(&pSurface->events.destroy, &PNODE->listen_destroy); + wl_signal_add(&pSurface->events.new_subsurface, &PNODE->listen_newSubsurface); + + return PNODE; +} + +SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface) { + const auto PNODE = createTree(surface); + PNODE->pParent = pParent; + PNODE->pSubsurface = pSubsurface; + + return PNODE; +} + +SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data) { + const auto PNODE = createTree(pSurface); + PNODE->offsetfn = fn; + PNODE->globalOffsetData = data; + + return PNODE; +} + +void destroySubsurface(SSubsurface* pSubsurface); + +void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) { + for (auto& c : pNode->childSubsurfaces) + destroySubsurface(&c); + + pNode->childSubsurfaces.clear(); + + wl_list_remove(&pNode->listen_newSubsurface.link); + wl_list_remove(&pNode->listen_commit.link); + wl_list_remove(&pNode->listen_destroy.link); + + Debug::log(LOG, "SurfaceTree Node removed"); +} + +void destroySubsurface(SSubsurface* pSubsurface) { + if (pSubsurface->pChild) { + SubsurfaceTree::destroySurfaceTree(pSubsurface->pChild); + pSubsurface->pChild = nullptr; + } + + wl_list_remove(&pSubsurface->listen_map.link); + wl_list_remove(&pSubsurface->listen_unmap.link); + wl_list_remove(&pSubsurface->listen_destroy.link); +} + +// +// Subsurface listeners +// + +void Events::listener_newSubsurfaceNode(wl_listener* listener, void* data) { + SSurfaceTreeNode* pNode = wl_container_of(listener, pNode, listen_newSubsurface); + + const auto PSUBSURFACE = (wlr_subsurface*)data; + + pNode->childSubsurfaces.push_back(SSubsurface()); + const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.back(); + + Debug::log(LOG, "Added a new subsurface %x", PSUBSURFACE); + + PNEWSUBSURFACE->pSubsurface = PSUBSURFACE; + PNEWSUBSURFACE->pParent = pNode; + + PNEWSUBSURFACE->listen_map.notify = Events::listener_mapSubsurface; + PNEWSUBSURFACE->listen_unmap.notify = Events::listener_unmapSubsurface; + PNEWSUBSURFACE->listen_destroy.notify = Events::listener_destroySubsurface; + + wl_signal_add(&PSUBSURFACE->events.map, &PNEWSUBSURFACE->listen_map); + wl_signal_add(&PSUBSURFACE->events.unmap, &PNEWSUBSURFACE->listen_unmap); + wl_signal_add(&PSUBSURFACE->events.destroy, &PNEWSUBSURFACE->listen_destroy); +} + +void Events::listener_mapSubsurface(wl_listener* listener, void* data) { + SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_map); + + Debug::log(LOG, "Subsurface %x mapped", subsurface->pSubsurface); + + subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface); +} + +void Events::listener_unmapSubsurface(wl_listener* listener, void* data) { + SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_unmap); + + Debug::log(LOG, "Subsurface %x unmapped", subsurface); + + if (subsurface->pChild) { + const auto PNODE = subsurface->pChild; + + int lx = 0, ly = 0; + addSurfaceGlobalOffset(PNODE, &lx, &ly); + + wlr_box extents = {0}; + wlr_surface_get_extends(PNODE->pSurface, &extents); + + extents.x += lx; + extents.y += ly; + + SubsurfaceTree::destroySurfaceTree(subsurface->pChild); + subsurface->pChild = nullptr; + } +} + +void Events::listener_commitSubsurface(wl_listener* listener, void* data) { + SSurfaceTreeNode* pNode = wl_container_of(listener, pNode, listen_commit); +} + +void Events::listener_destroySubsurface(wl_listener* listener, void* data) { + SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_destroy); + + Debug::log(LOG, "Subsurface %x destroyed", subsurface); + + subsurface->pParent->childSubsurfaces.remove(*subsurface); +} + +void Events::listener_destroySubsurfaceNode(wl_listener* listener, void* data) { + SSurfaceTreeNode* pNode = wl_container_of(listener, pNode, listen_destroy); + + Debug::log(LOG, "Subsurface Node %x destroyed", pNode); + + for (auto& c : pNode->childSubsurfaces) + destroySubsurface(&c); + + wl_list_remove(&pNode->listen_newSubsurface.link); + wl_list_remove(&pNode->listen_commit.link); + wl_list_remove(&pNode->listen_destroy.link); + + SubsurfaceTree::surfaceTreeNodes.remove(*pNode); +} \ No newline at end of file diff --git a/src/helpers/SubsurfaceTree.hpp b/src/helpers/SubsurfaceTree.hpp new file mode 100644 index 00000000..df92033a --- /dev/null +++ b/src/helpers/SubsurfaceTree.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "../defines.hpp" +#include + +struct SSubsurface; + +typedef void (*applyGlobalOffsetFn)(void *, int *, int *); + +struct SSurfaceTreeNode { + wlr_surface* pSurface = nullptr; + + DYNMULTILISTENER(newSubsurface); + DYNMULTILISTENER(commit); + DYNMULTILISTENER(destroy); + + SSurfaceTreeNode* pParent = nullptr; + SSubsurface* pSubsurface = nullptr; + + std::list childSubsurfaces; + + applyGlobalOffsetFn offsetfn; + void *globalOffsetData; + + bool operator==(const SSurfaceTreeNode& rhs) { + return pSurface == rhs.pSurface; + } +}; + +struct SSubsurface { + wlr_subsurface* pSubsurface = nullptr; + + SSurfaceTreeNode* pParent = nullptr; + SSurfaceTreeNode* pChild = nullptr; + + DYNMULTILISTENER(map); + DYNMULTILISTENER(unmap); + DYNMULTILISTENER(destroy); + + bool operator==(const SSubsurface& rhs) { + return pSubsurface == rhs.pSubsurface; + } +}; + +namespace SubsurfaceTree { + SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*); + void destroySurfaceTree(SSurfaceTreeNode*); + + inline std::list surfaceTreeNodes; +}; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 791e69f2..985e62af 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -4,6 +4,7 @@ #include "../defines.hpp" #include "../../wlr-layer-shell-unstable-v1-protocol.h" #include "../Window.hpp" +#include "SubsurfaceTree.hpp" struct SLayerSurface { wlr_layer_surface_v1* layerSurface; @@ -14,9 +15,9 @@ struct SLayerSurface { DYNLISTENER(unmapLayerSurface); DYNLISTENER(commitLayerSurface); DYNLISTENER(newPopup); - DYNLISTENER(newSubsurface); wlr_box geometry; + Vector2D position; zwlr_layer_shell_v1_layer layer; int monitorID = -1; @@ -28,22 +29,6 @@ struct SLayerSurface { } }; -struct SSubsurface { - wlr_subsurface* subsurface = nullptr; - SLayerSurface* pParentSurface = nullptr; - - DYNLISTENER(mapSubsurface); - DYNLISTENER(unmapSubsurface); - DYNLISTENER(destroySubsurface); - DYNLISTENER(commitSubsurface); - DYNLISTENER(newSubsurface); - - // For the list lookup - bool operator==(const SSubsurface& rhs) { - return subsurface == rhs.subsurface && pParentSurface == rhs.pParentSurface; - } -}; - struct SRenderData { wlr_output* output; timespec* when; @@ -68,26 +53,9 @@ struct SKeyboard { } }; -struct SLayerPopup { - wlr_xdg_popup* popup = nullptr; - SLayerSurface* parentSurface = nullptr; - wlr_xdg_popup* parentPopup = nullptr; - - DYNLISTENER(mapPopup); - DYNLISTENER(destroyPopup); - DYNLISTENER(unmapPopup); - DYNLISTENER(commitPopup); - DYNLISTENER(newPopupFromPopup); - - // For the list lookup - bool operator==(const SLayerPopup& rhs) { - return popup == rhs.popup; - } -}; - struct SXDGPopup { CWindow* parentWindow = nullptr; - wlr_xdg_popup* parentPopup = nullptr; + SXDGPopup* parentPopup = nullptr; wlr_xdg_popup* popup = nullptr; DYNLISTENER(newPopupFromPopupXDG); @@ -95,6 +63,11 @@ struct SXDGPopup { DYNLISTENER(mapPopupXDG); DYNLISTENER(unmapPopupXDG); + double* lx; + double* ly; + + SSurfaceTreeNode* pSurfaceTree = nullptr; + // For the list lookup bool operator==(const SXDGPopup& rhs) { return popup == rhs.popup; -- cgit v1.2.3