mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 16:46:00 +01:00
subsurface: Rewrite the subsurface tree (#4877)
This commit is contained in:
parent
1e7eb3a5a5
commit
b1c0f1cc01
11 changed files with 312 additions and 414 deletions
|
@ -95,7 +95,6 @@ class CCompositor {
|
||||||
std::vector<std::unique_ptr<CWindow>> m_vWindows;
|
std::vector<std::unique_ptr<CWindow>> m_vWindows;
|
||||||
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
|
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
|
||||||
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces;
|
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces;
|
||||||
std::vector<std::unique_ptr<SSubsurface>> m_vSubsurfaces;
|
|
||||||
std::vector<CWindow*> m_vWindowsFadingOut;
|
std::vector<CWindow*> m_vWindowsFadingOut;
|
||||||
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
|
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
|
||||||
|
|
||||||
|
|
|
@ -471,6 +471,8 @@ void CWindow::onUnmap() {
|
||||||
PMONITOR->solitaryClient = nullptr;
|
PMONITOR->solitaryClient = nullptr;
|
||||||
|
|
||||||
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
|
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
|
||||||
|
|
||||||
|
m_pSubsurfaceHead.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::onMap() {
|
void CWindow::onMap() {
|
||||||
|
@ -516,6 +518,8 @@ void CWindow::onMap() {
|
||||||
m_bTearingHint = ctrl->pWlrHint->current;
|
m_bTearingHint = ctrl->pWlrHint->current;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "helpers/SubsurfaceTree.hpp"
|
#include "helpers/Subsurface.hpp"
|
||||||
#include "helpers/AnimatedVariable.hpp"
|
#include "helpers/AnimatedVariable.hpp"
|
||||||
#include "render/decorations/IHyprWindowDecoration.hpp"
|
#include "render/decorations/IHyprWindowDecoration.hpp"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
@ -276,9 +276,10 @@ class CWindow {
|
||||||
bool m_bWantsInitialFullscreen = false;
|
bool m_bWantsInitialFullscreen = false;
|
||||||
|
|
||||||
// bitfield eSuppressEvents
|
// 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<CSubsurface> m_pSubsurfaceHead;
|
||||||
|
|
||||||
// Animated border
|
// Animated border
|
||||||
CGradientValueData m_cRealBorderColor = {0};
|
CGradientValueData m_cRealBorderColor = {0};
|
||||||
|
|
|
@ -22,14 +22,6 @@ namespace Events {
|
||||||
DYNLISTENFUNC(unmapLayerSurface);
|
DYNLISTENFUNC(unmapLayerSurface);
|
||||||
DYNLISTENFUNC(commitLayerSurface);
|
DYNLISTENFUNC(commitLayerSurface);
|
||||||
|
|
||||||
// Subsurfaces
|
|
||||||
DYNLISTENFUNC(newSubsurfaceNode);
|
|
||||||
DYNLISTENFUNC(destroySubsurfaceNode);
|
|
||||||
DYNLISTENFUNC(mapSubsurface);
|
|
||||||
DYNLISTENFUNC(unmapSubsurface);
|
|
||||||
DYNLISTENFUNC(destroySubsurface);
|
|
||||||
DYNLISTENFUNC(commitSubsurface);
|
|
||||||
|
|
||||||
// Popups
|
// Popups
|
||||||
DYNLISTENFUNC(newPopup); // LayerSurface
|
DYNLISTENFUNC(newPopup); // LayerSurface
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
|
||||||
else if (PPOPUP->parentLS)
|
else if (PPOPUP->parentLS)
|
||||||
PPOPUP->parentLS->popupSurfaces.emplace_back(PPOPUP->popup->base->surface);
|
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;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
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);
|
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) {
|
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)
|
if (PPOPUP->popup->base->surface == g_pCompositor->m_pLastFocus)
|
||||||
g_pInputManager->releaseAllMouseButtons();
|
g_pInputManager->releaseAllMouseButtons();
|
||||||
|
|
||||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
// SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||||
|
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
addPopupGlobalCoords(PPOPUP, &lx, &ly);
|
||||||
|
@ -220,7 +220,7 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||||
else if (PPOPUP->parentLS)
|
else if (PPOPUP->parentLS)
|
||||||
std::erase(PPOPUP->parentLS->popupSurfaces, PPOPUP->popup->base->surface);
|
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
|
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);
|
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
|
||||||
|
|
||||||
if (PPOPUP->pSurfaceTree) {
|
// if (PPOPUP->pSurfaceTree) {
|
||||||
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
// SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
|
||||||
PPOPUP->pSurfaceTree = nullptr;
|
// PPOPUP->pSurfaceTree = nullptr;
|
||||||
}
|
// }
|
||||||
|
|
||||||
std::erase_if(g_pCompositor->m_vXDGPopups, [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; });
|
std::erase_if(g_pCompositor->m_vXDGPopups, [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; });
|
||||||
}
|
}
|
||||||
|
|
|
@ -486,8 +486,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||||
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
|
|
||||||
|
|
||||||
if (!PWINDOW->m_bIsX11) {
|
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_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");
|
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
|
// recheck idle inhibitors
|
||||||
g_pInputManager->recheckIdleInhibitorStatus();
|
g_pInputManager->recheckIdleInhibitorStatus();
|
||||||
|
|
||||||
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(PWINDOW->m_pWLSurface.wlr(), addViewCoords, PWINDOW, PWINDOW);
|
|
||||||
|
|
||||||
PWINDOW->updateToplevel();
|
PWINDOW->updateToplevel();
|
||||||
|
|
||||||
if (workspaceSilent) {
|
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, "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;
|
PWINDOW->m_bFadingOut = true;
|
||||||
|
|
||||||
g_pCompositor->addToFadingOutSafe(PWINDOW);
|
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,
|
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_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
|
||||||
|
|
||||||
|
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
|
||||||
|
|
||||||
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -895,12 +888,6 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||||
|
|
||||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
|
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;
|
PWINDOW->m_bReadyToDelete = true;
|
||||||
|
|
||||||
if (!PWINDOW->m_bFadingOut) {
|
if (!PWINDOW->m_bFadingOut) {
|
||||||
|
|
238
src/helpers/Subsurface.cpp
Normal file
238
src/helpers/Subsurface.cpp
Normal file
|
@ -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<CSubsurface>(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);
|
||||||
|
}
|
||||||
|
}
|
51
src/helpers/Subsurface.hpp
Normal file
51
src/helpers/Subsurface.hpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../defines.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#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<std::unique_ptr<CSubsurface>> m_vChildren;
|
||||||
|
|
||||||
|
void initSignals();
|
||||||
|
void initExistingSubsurfaces();
|
||||||
|
void checkSiblingDamage();
|
||||||
|
};
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../defines.hpp"
|
|
||||||
#include <list>
|
|
||||||
#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<SSubsurface> 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<SSurfaceTreeNode> surfaceTreeNodes;
|
|
||||||
};
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
||||||
#include "../Window.hpp"
|
#include "../Window.hpp"
|
||||||
#include "SubsurfaceTree.hpp"
|
#include "Subsurface.hpp"
|
||||||
#include "AnimatedVariable.hpp"
|
#include "AnimatedVariable.hpp"
|
||||||
#include "WLSurface.hpp"
|
#include "WLSurface.hpp"
|
||||||
#include "Region.hpp"
|
#include "Region.hpp"
|
||||||
|
@ -213,13 +213,11 @@ struct SXDGPopup {
|
||||||
DYNLISTENER(commitPopupXDG);
|
DYNLISTENER(commitPopupXDG);
|
||||||
DYNLISTENER(repositionPopupXDG);
|
DYNLISTENER(repositionPopupXDG);
|
||||||
|
|
||||||
double lx;
|
double lx;
|
||||||
double ly;
|
double ly;
|
||||||
|
|
||||||
Vector2D lastPos = {};
|
Vector2D lastPos = {};
|
||||||
bool repositionRequested = false;
|
bool repositionRequested = false;
|
||||||
|
|
||||||
SSurfaceTreeNode* pSurfaceTree = nullptr;
|
|
||||||
|
|
||||||
// For the list lookup
|
// For the list lookup
|
||||||
bool operator==(const SXDGPopup& rhs) const {
|
bool operator==(const SXDGPopup& rhs) const {
|
||||||
|
|
Loading…
Reference in a new issue