Hyprland/src/helpers/SubsurfaceTree.cpp

246 lines
8.4 KiB
C++
Raw Permalink Normal View History

2022-03-27 17:25:20 +02:00
#include "SubsurfaceTree.hpp"
#include "../events/Events.hpp"
2022-04-14 16:43:29 +02:00
#include "../Compositor.hpp"
2022-03-27 17:25:20 +02:00
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, CWindow* pWindow) {
2022-07-26 21:41:29 +02:00
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.emplace_back();
2022-03-27 17:25:20 +02:00
PNODE->pSurface = pSurface;
PNODE->pWindowOwner = pWindow;
2022-03-27 17:25:20 +02:00
2022-03-28 22:31:39 +02:00
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");
2022-03-27 17:25:20 +02:00
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);
}
2022-03-27 17:25:20 +02:00
return PNODE;
}
SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface, CWindow* pWindow) {
const auto PNODE = createTree(surface, pWindow);
2022-03-27 17:25:20 +02:00
PNODE->pParent = pParent;
PNODE->pSubsurface = pSubsurface;
Debug::log(LOG, "Creating a subsurface Node! (pWindow: %x)", pWindow);
2022-03-27 17:25:20 +02:00
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: %x)", pWindow);
2022-03-27 17:25:20 +02:00
PNODE->offsetfn = fn;
PNODE->globalOffsetData = data;
return PNODE;
}
void destroySubsurface(SSubsurface* pSubsurface);
void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
2022-03-27 22:34:02 +02:00
bool exists = false;
for (auto& n : surfaceTreeNodes) {
if (&n == pNode) {
exists = true;
break;
}
}
2022-03-28 21:16:23 +02:00
if (!exists) {
Debug::log(ERR, "Tried to remove a SurfaceTreeNode that doesn't exist?? (Node %x)", pNode);
return;
}
2022-03-27 17:25:20 +02:00
for (auto& c : pNode->childSubsurfaces)
destroySubsurface(&c);
pNode->childSubsurfaces.clear();
2022-03-28 22:31:39 +02:00
pNode->hyprListener_commit.removeCallback();
pNode->hyprListener_destroy.removeCallback();
pNode->hyprListener_newSubsurface.removeCallback();
2022-03-27 17:25:20 +02:00
2022-06-05 23:23:16 +02:00
// damage
if (pNode->pSurface) {
wlr_box extents = {};
wlr_surface_get_extends(pNode->pSurface, &extents);
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
extents.x += lx;
extents.y += ly;
g_pHyprRenderer->damageBox(&extents);
}
2022-04-10 16:19:49 +02:00
surfaceTreeNodes.remove(*pNode);
2022-03-27 17:25:20 +02:00
Debug::log(LOG, "SurfaceTree Node removed");
}
void destroySubsurface(SSubsurface* pSubsurface) {
if (pSubsurface->pChild) {
SubsurfaceTree::destroySurfaceTree(pSubsurface->pChild);
pSubsurface->pChild = nullptr;
}
2022-03-28 22:31:39 +02:00
pSubsurface->hyprListener_destroy.removeCallback();
pSubsurface->hyprListener_map.removeCallback();
pSubsurface->hyprListener_unmap.removeCallback();
2022-03-27 17:25:20 +02:00
}
//
// Subsurface listeners
//
2022-03-28 22:31:39 +02:00
void Events::listener_newSubsurfaceNode(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
2022-03-27 17:25:20 +02:00
const auto PSUBSURFACE = (wlr_subsurface*)data;
2022-07-26 21:41:29 +02:00
const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.emplace_back();
2022-03-27 17:25:20 +02:00
Debug::log(LOG, "Added a new subsurface %x", PSUBSURFACE);
PNEWSUBSURFACE->pSubsurface = PSUBSURFACE;
PNEWSUBSURFACE->pParent = pNode;
2022-03-28 22:31:39 +02:00
PNEWSUBSURFACE->hyprListener_map.initCallback(&PSUBSURFACE->events.map, &Events::listener_mapSubsurface, PNEWSUBSURFACE, "Subsurface");
2022-04-10 15:36:44 +02:00
PNEWSUBSURFACE->hyprListener_unmap.initCallback(&PSUBSURFACE->events.unmap, &Events::listener_unmapSubsurface, PNEWSUBSURFACE, "Subsurface");
2022-03-28 22:31:39 +02:00
PNEWSUBSURFACE->hyprListener_destroy.initCallback(&PSUBSURFACE->events.destroy, &Events::listener_destroySubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
if (PSUBSURFACE->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);
}
2022-03-27 17:25:20 +02:00
}
2022-03-28 22:31:39 +02:00
void Events::listener_mapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
2022-03-27 17:25:20 +02:00
Debug::log(LOG, "Subsurface %x mapped", subsurface->pSubsurface);
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
2022-03-27 17:25:20 +02:00
}
2022-03-28 22:31:39 +02:00
void Events::listener_unmapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
2022-03-27 17:25:20 +02:00
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};
2022-07-19 13:54:42 +02:00
if (PNODE->pSurface) {
wlr_surface_get_extends(PNODE->pSurface, &extents);
2022-03-27 17:25:20 +02:00
2022-07-19 13:54:42 +02:00
extents.x += lx;
extents.y += ly;
2022-03-27 17:25:20 +02:00
2022-07-19 13:54:42 +02:00
g_pHyprRenderer->damageBox(&extents);
}
2022-06-05 23:23:16 +02:00
2022-03-27 17:25:20 +02:00
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
subsurface->pChild = nullptr;
}
}
2022-03-28 22:31:39 +02:00
void Events::listener_commitSubsurface(void* owner, void* data) {
2022-04-02 13:41:15 +02:00
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
// no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
2022-08-27 21:37:35 +02:00
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from %x because it's invisible.", pNode->pWindowOwner);
return;
}
2022-04-02 13:41:15 +02:00
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
2022-04-14 16:43:29 +02:00
2022-06-28 15:30:46 +02:00
// 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);
}
}
2022-04-14 16:43:29 +02:00
g_pHyprRenderer->damageSurface(pNode->pSurface, lx, ly);
2022-03-27 17:25:20 +02:00
}
2022-03-28 22:31:39 +02:00
void Events::listener_destroySubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
2022-03-27 17:25:20 +02:00
2022-04-10 15:36:44 +02:00
if (subsurface->pChild)
listener_destroySubsurfaceNode(subsurface->pChild, nullptr);
2022-03-27 17:25:20 +02:00
Debug::log(LOG, "Subsurface %x destroyed", subsurface);
2022-04-02 18:57:09 +02:00
subsurface->hyprListener_destroy.removeCallback();
subsurface->hyprListener_map.removeCallback();
subsurface->hyprListener_unmap.removeCallback();
2022-03-27 17:25:20 +02:00
subsurface->pParent->childSubsurfaces.remove(*subsurface);
}
2022-03-28 22:31:39 +02:00
void Events::listener_destroySubsurfaceNode(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
2022-03-27 17:25:20 +02:00
Debug::log(LOG, "Subsurface Node %x destroyed", pNode);
for (auto& c : pNode->childSubsurfaces)
destroySubsurface(&c);
2022-03-28 22:31:39 +02:00
pNode->hyprListener_commit.removeCallback();
pNode->hyprListener_newSubsurface.removeCallback();
pNode->hyprListener_destroy.removeCallback();
2022-03-27 17:25:20 +02:00
SubsurfaceTree::surfaceTreeNodes.remove(*pNode);
2022-03-27 22:34:02 +02:00
}