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: [PATCH] rework popups completely --- src/Compositor.cpp | 14 --- src/Compositor.hpp | 2 - src/Window.hpp | 2 +- src/defines.hpp | 8 +- src/events/Events.hpp | 18 ++-- src/events/Layers.cpp | 81 +--------------- src/events/Popups.cpp | 163 ++++++++++++++------------------- src/events/Windows.cpp | 55 +---------- src/helpers/SubsurfaceTree.cpp | 163 +++++++++++++++++++++++++++++++++ src/helpers/SubsurfaceTree.hpp | 50 ++++++++++ src/helpers/WLClasses.hpp | 43 ++------- 11 files changed, 314 insertions(+), 285 deletions(-) create mode 100644 src/helpers/SubsurfaceTree.cpp create mode 100644 src/helpers/SubsurfaceTree.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index eab48614..5405a4f0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -365,20 +365,6 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) { return true; } -SLayerSurface* CCompositor::getLayerForPopup(SLayerPopup* pPopup) { - auto CurrentPopup = pPopup; - while (CurrentPopup->parentPopup != nullptr) { - for (auto& p : g_pCompositor->m_lLayerPopups) { - if (p.popup == CurrentPopup->parentPopup) { - CurrentPopup = &p; - break; - } - } - } - - return CurrentPopup->parentSurface; -} - CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) { for (auto& p : m_lXDGPopups) { if (p.popup == popup) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index fad078b4..5d67356d 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -53,7 +53,6 @@ public: std::list m_lMonitors; std::list m_lWindows; - std::list m_lLayerPopups; std::list m_lXDGPopups; std::list m_lWorkspaces; std::list m_lSubsurfaces; @@ -82,7 +81,6 @@ public: CWindow* windowFromCursor(); CWindow* windowFloatingFromCursor(); SMonitor* getMonitorFromOutput(wlr_output*); - SLayerSurface* getLayerForPopup(SLayerPopup*); CWindow* getWindowForPopup(wlr_xdg_popup*); CWindow* getWindowFromSurface(wlr_surface*); bool isWorkspaceVisible(const int&); diff --git a/src/Window.hpp b/src/Window.hpp index 08e539cb..9626bbc6 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -14,7 +14,7 @@ public: DYNLISTENER(setTitleWindow); DYNLISTENER(fullscreenWindow); DYNLISTENER(newPopupXDG); - DYNLISTENER(newSubsurfaceWindow); + // DYNLISTENER(newSubsurfaceWindow); union { wlr_xdg_surface* xdg; diff --git a/src/defines.hpp b/src/defines.hpp index 0be79cb6..ff7588e0 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -1,4 +1,5 @@ #include "includes.hpp" +#include "debug/Log.hpp" #ifndef NDEBUG #define ISDEBUG true @@ -10,6 +11,7 @@ #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 DYNMULTILISTENER(name) wl_listener listen_##name; #define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2)) @@ -22,4 +24,8 @@ #define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0) #define BLUE(c) ((double)(((c)) & 0xff) / 255.0) -#define HYPRATOM(name) {name, 0} \ No newline at end of file +#define HYPRATOM(name) {name, 0} + +#define RASSERT(expr, reason) if (expr) { Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n%s\n\nat: line %s in %s", reason, __LINE__, __FILE__); RIP("Assertion failed! See the log in /tmp/hypr/hyprland.log for more info.");} + +#define ASSERT(expr) RASSERT(expr, "?") \ No newline at end of file diff --git a/src/events/Events.hpp b/src/events/Events.hpp index b7fac9d6..bcd3d87b 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -1,6 +1,12 @@ #pragma once #include "../defines.hpp" +// +// LISTEN_NAME -> the wl_listener +// +// LISTENER_NAME -> the wl_listener.notify function +// + namespace Events { // Monitor events LISTENER(change); @@ -14,19 +20,15 @@ namespace Events { LISTENER(commitLayerSurface); // Subsurfaces - LISTENER(newSubsurface); + LISTENER(newSubsurfaceNode); + LISTENER(destroySubsurfaceNode); LISTENER(mapSubsurface); LISTENER(unmapSubsurface); LISTENER(destroySubsurface); LISTENER(commitSubsurface); // Popups - LISTENER(newPopup); - LISTENER(newPopupFromPopup); - LISTENER(mapPopup); - LISTENER(unmapPopup); - LISTENER(destroyPopup); - LISTENER(commitPopup); + LISTENER(newPopup); // LayerSurface LISTENER(newPopupXDG); LISTENER(mapPopupXDG); @@ -49,7 +51,7 @@ namespace Events { LISTENER(configureX11); // Window subsurfaces - LISTENER(newSubsurfaceWindow); + // LISTENER(newSubsurfaceWindow); // Input events LISTENER(mouseMove); diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp index 6b4f0a1a..4fc9848f 100644 --- a/src/events/Layers.cpp +++ b/src/events/Layers.cpp @@ -44,7 +44,6 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) { wl_signal_add(&WLRLAYERSURFACE->events.map, &layerSurface->listen_mapLayerSurface); wl_signal_add(&WLRLAYERSURFACE->events.unmap, &layerSurface->listen_unmapLayerSurface); wl_signal_add(&WLRLAYERSURFACE->events.new_popup, &layerSurface->listen_newPopup); - wl_signal_add(&WLRLAYERSURFACE->surface->events.new_subsurface, &layerSurface->listen_newSubsurface); layerSurface->layerSurface = WLRLAYERSURFACE; layerSurface->layer = WLRLAYERSURFACE->current.layer; @@ -108,6 +107,8 @@ void Events::listener_mapLayerSurface(wl_listener* listener, void* data) { if (layersurface->layerSurface->current.keyboard_interactive) g_pCompositor->focusSurface(layersurface->layerSurface->surface); + + layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y); } void Events::listener_unmapLayerSurface(wl_listener* listener, void* data) { @@ -152,82 +153,6 @@ void Events::listener_commitLayerSurface(wl_listener* listener, void* data) { } g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID); -} -// -// Subsurfaces -// - -void createSubsurface(wlr_subsurface* pSubSurface, SLayerSurface* pLayerSurface) { - if (!pSubSurface || !pLayerSurface) - return; - - Debug::log(LOG, "Subsurface %x created", pSubSurface); - - g_pCompositor->m_lSubsurfaces.push_back(SSubsurface()); - const auto PNEWSUBSURFACE = &g_pCompositor->m_lSubsurfaces.back(); - - PNEWSUBSURFACE->subsurface = pSubSurface; - PNEWSUBSURFACE->pParentSurface = pLayerSurface; - - wl_signal_add(&pSubSurface->events.map, &PNEWSUBSURFACE->listen_mapSubsurface); - wl_signal_add(&pSubSurface->events.unmap, &PNEWSUBSURFACE->listen_unmapSubsurface); - wl_signal_add(&pSubSurface->events.destroy, &PNEWSUBSURFACE->listen_destroySubsurface); - wl_signal_add(&pSubSurface->surface->events.commit, &PNEWSUBSURFACE->listen_commitSubsurface); -} - -void damageSubsurface(SSubsurface* subSurface, bool all = false) { - if (!subSurface->pParentSurface->layerSurface->output) - return; - - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(subSurface->pParentSurface->layerSurface->output); - - if (!PMONITOR) - return; // wut? - - int x = subSurface->subsurface->current.x + subSurface->pParentSurface->geometry.x; - int y = subSurface->subsurface->current.y + subSurface->pParentSurface->geometry.y; - - g_pHyprRenderer->damageSurface(PMONITOR, x, y, subSurface->subsurface->surface, &all); -} - -void Events::listener_newSubsurface(wl_listener* listener, void* data) { - SLayerSurface* layersurface = wl_container_of(listener, layersurface, listen_newSubsurface); - - createSubsurface((wlr_subsurface*)data, layersurface); -} - -void Events::listener_mapSubsurface(wl_listener* listener, void* data) { - SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_mapSubsurface); - - Debug::log(LOG, "Subsurface %x mapped", subsurface); - - damageSubsurface(subsurface, true); -} - -void Events::listener_unmapSubsurface(wl_listener* listener, void* data) { - SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_unmapSubsurface); - - Debug::log(LOG, "Subsurface %x unmapped", subsurface); - - damageSubsurface(subsurface, true); -} - -void Events::listener_commitSubsurface(wl_listener* listener, void* data) { - SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_commitSubsurface); - - damageSubsurface(subsurface, false); -} - -void Events::listener_destroySubsurface(wl_listener* listener, void* data) { - SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_destroySubsurface); - - Debug::log(LOG, "Subsurface %x destroyed", subsurface); - - wl_list_remove(&subsurface->listen_mapSubsurface.link); - wl_list_remove(&subsurface->listen_unmapSubsurface.link); - wl_list_remove(&subsurface->listen_destroySubsurface.link); - wl_list_remove(&subsurface->listen_commitSubsurface.link); - - g_pCompositor->m_lSubsurfaces.remove(*subsurface); + layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y); } \ No newline at end of file diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp index 78d841fe..a85fa4b5 100644 --- a/src/events/Popups.cpp +++ b/src/events/Popups.cpp @@ -15,32 +15,49 @@ // // // --------------------------------------------- // -void createNewPopup(wlr_xdg_popup* popup, void* parent, bool parentIsLayer) { +void addPopupGlobalCoords(void* pPopup, int* x, int* y) { + SXDGPopup *const PPOPUP = (SXDGPopup*)pPopup; - if (!popup) - return; + int px = 0; + int py = 0; - g_pCompositor->m_lLayerPopups.push_back(SLayerPopup()); - const auto PNEWPOPUP = &g_pCompositor->m_lLayerPopups.back(); + auto curPopup = PPOPUP; + while (true) { + px += curPopup->popup->geometry.x; + py += curPopup->popup->geometry.y; - PNEWPOPUP->popup = popup; - if (parentIsLayer) - PNEWPOPUP->parentSurface = (SLayerSurface*)parent; - else - PNEWPOPUP->parentPopup = (wlr_xdg_popup*)parent; + if (curPopup->parentPopup) { + curPopup = curPopup->parentPopup; + } else { + break; + } + } - wl_signal_add(&popup->base->events.map, &PNEWPOPUP->listen_mapPopup); - wl_signal_add(&popup->base->events.unmap, &PNEWPOPUP->listen_unmapPopup); - wl_signal_add(&popup->base->events.destroy, &PNEWPOPUP->listen_destroyPopup); - wl_signal_add(&popup->base->events.new_popup, &PNEWPOPUP->listen_newPopupFromPopup); - wl_signal_add(&popup->base->surface->events.commit, &PNEWPOPUP->listen_commitPopup); + px += *PPOPUP->lx; + py += *PPOPUP->ly; - const auto PLAYER = g_pCompositor->getLayerForPopup(PNEWPOPUP); - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(PLAYER->layerSurface->output); + *x += px; + *y += py; +} + +void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) { + pHyprPopup->popup = popup; + + pHyprPopup->listen_mapPopupXDG.notify = Events::listener_mapPopupXDG; + pHyprPopup->listen_unmapPopupXDG.notify = Events::listener_unmapPopupXDG; + pHyprPopup->listen_destroyPopupXDG.notify = Events::listener_destroyPopupXDG; + pHyprPopup->listen_newPopupFromPopupXDG.notify = Events::listener_newPopupXDG; + + wl_signal_add(&popup->base->events.map, &pHyprPopup->listen_mapPopupXDG); + wl_signal_add(&popup->base->events.unmap, &pHyprPopup->listen_unmapPopupXDG); + wl_signal_add(&popup->base->surface->events.destroy, &pHyprPopup->listen_destroyPopupXDG); + wl_signal_add(&popup->base->events.new_popup, &pHyprPopup->listen_newPopupFromPopupXDG); + + const auto PMONITOR = g_pCompositor->m_pLastMonitor; wlr_box box = {.x = PMONITOR->vecPosition.x, .y = PMONITOR->vecPosition.y, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y}; - wlr_xdg_popup_unconstrain_from_box(PNEWPOPUP->popup, &box); + wlr_xdg_popup_unconstrain_from_box(popup, &box); } void Events::listener_newPopup(wl_listener* listener, void* data) { @@ -50,81 +67,13 @@ void Events::listener_newPopup(wl_listener* listener, void* data) { const auto WLRPOPUP = (wlr_xdg_popup*)data; - createNewPopup(WLRPOPUP, layersurface, true); -} - -void Events::listener_newPopupFromPopup(wl_listener* listener, void* data) { - SLayerPopup* layerPopup = wl_container_of(listener, layerPopup, listen_newPopupFromPopup); - - Debug::log(LOG, "New layer popup created from popup %x", layerPopup); - - const auto WLRPOPUP = (wlr_xdg_popup*)data; - - createNewPopup(WLRPOPUP, layerPopup, true); -} - -void Events::listener_destroyPopup(wl_listener* listener, void* data) { - SLayerPopup* layerPopup = wl_container_of(listener, layerPopup, listen_destroyPopup); - - Debug::log(LOG, "Destroyed popup %x", layerPopup); - - wl_list_remove(&layerPopup->listen_mapPopup.link); - wl_list_remove(&layerPopup->listen_unmapPopup.link); - wl_list_remove(&layerPopup->listen_destroyPopup.link); - wl_list_remove(&layerPopup->listen_commitPopup.link); - - g_pCompositor->m_lLayerPopups.remove(*layerPopup); -} - -void Events::listener_mapPopup(wl_listener* listener, void* data) { - SLayerPopup* layerPopup = wl_container_of(listener, layerPopup, listen_mapPopup); - - Debug::log(LOG, "Mapped popup %x", layerPopup); - - const auto PLAYER = g_pCompositor->getLayerForPopup(layerPopup); - - wlr_surface_send_enter(layerPopup->popup->base->surface, PLAYER->layerSurface->output); -} - -void Events::listener_unmapPopup(wl_listener* listener, void* data) { - SLayerPopup* layerPopup = wl_container_of(listener, layerPopup, listen_unmapPopup); - - Debug::log(LOG, "LayerPopup %x unmapped", layerPopup); -} - -void Events::listener_commitPopup(wl_listener* listener, void* data) { - SLayerPopup* layerPopup = wl_container_of(listener, layerPopup, listen_commitPopup); - -} - -void createNewPopupXDG(wlr_xdg_popup* popup, void* parent, bool parentIsWindow) { - if (!popup) - return; - - Debug::log(LOG, "New XDG Popup %x created", popup); - g_pCompositor->m_lXDGPopups.push_back(SXDGPopup()); const auto PNEWPOPUP = &g_pCompositor->m_lXDGPopups.back(); - PNEWPOPUP->popup = popup; - if (parentIsWindow) - PNEWPOPUP->parentWindow = (CWindow*)parent; - else { - PNEWPOPUP->parentPopup = (wlr_xdg_popup*)parent; - PNEWPOPUP->parentWindow = g_pCompositor->getWindowForPopup((wlr_xdg_popup*)parent); - } - - - wl_signal_add(&popup->base->events.map, &PNEWPOPUP->listen_mapPopupXDG); - wl_signal_add(&popup->base->events.unmap, &PNEWPOPUP->listen_unmapPopupXDG); - wl_signal_add(&popup->base->events.destroy, &PNEWPOPUP->listen_destroyPopupXDG); - wl_signal_add(&popup->base->events.new_popup, &PNEWPOPUP->listen_newPopupFromPopupXDG); - - const auto PMONITOR = g_pCompositor->getMonitorFromID(PNEWPOPUP->parentWindow->m_iMonitorID); - - wlr_box box = {.x = PMONITOR->vecPosition.x, .y = PMONITOR->vecPosition.y, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y}; - - wlr_xdg_popup_unconstrain_from_box(PNEWPOPUP->popup, &box); + PNEWPOPUP->popup = WLRPOPUP; + PNEWPOPUP->lx = &layersurface->position.x; + PNEWPOPUP->ly = &layersurface->position.y; + createNewPopup(WLRPOPUP, PNEWPOPUP); } void Events::listener_newPopupXDG(wl_listener* listener, void* data) { @@ -134,7 +83,13 @@ void Events::listener_newPopupXDG(wl_listener* listener, void* data) { const auto WLRPOPUP = (wlr_xdg_popup*)data; - createNewPopupXDG(WLRPOPUP, PWINDOW, true); + g_pCompositor->m_lXDGPopups.push_back(SXDGPopup()); + const auto PNEWPOPUP = &g_pCompositor->m_lXDGPopups.back(); + + PNEWPOPUP->popup = WLRPOPUP; + PNEWPOPUP->lx = &PWINDOW->m_vEffectivePosition.x; + PNEWPOPUP->ly = &PWINDOW->m_vEffectivePosition.y; + createNewPopup(WLRPOPUP, PNEWPOPUP); } void Events::listener_newPopupFromPopupXDG(wl_listener* listener, void* data) { @@ -144,15 +99,32 @@ void Events::listener_newPopupFromPopupXDG(wl_listener* listener, void* data) { const auto WLRPOPUP = (wlr_xdg_popup*)data; - createNewPopupXDG(WLRPOPUP, PPOPUP, true); + g_pCompositor->m_lXDGPopups.push_back(SXDGPopup()); + const auto PNEWPOPUP = &g_pCompositor->m_lXDGPopups.back(); + + PNEWPOPUP->popup = WLRPOPUP; + PNEWPOPUP->parentPopup = PPOPUP; + PNEWPOPUP->lx = PPOPUP->lx; + PNEWPOPUP->ly = PPOPUP->ly; + + createNewPopup(WLRPOPUP, PNEWPOPUP); } void Events::listener_mapPopupXDG(wl_listener* listener, void* data) { + SXDGPopup* PPOPUP = wl_container_of(listener, PPOPUP, listen_mapPopupXDG); + Debug::log(LOG, "New XDG Popup mapped"); + + PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP); } void Events::listener_unmapPopupXDG(wl_listener* listener, void* data) { + SXDGPopup* PPOPUP = wl_container_of(listener, PPOPUP, listen_unmapPopupXDG); Debug::log(LOG, "XDG Popup unmapped"); + + SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree); + + PPOPUP->pSurfaceTree = nullptr; } void Events::listener_destroyPopupXDG(wl_listener* listener, void* data) { @@ -160,9 +132,10 @@ void Events::listener_destroyPopupXDG(wl_listener* listener, void* data) { Debug::log(LOG, "Destroyed popup XDG %x", PPOPUP); - wl_list_remove(&PPOPUP->listen_mapPopupXDG.link); - wl_list_remove(&PPOPUP->listen_unmapPopupXDG.link); - wl_list_remove(&PPOPUP->listen_destroyPopupXDG.link); + if (PPOPUP->pSurfaceTree) { + SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree); + PPOPUP->pSurfaceTree = nullptr; + } g_pCompositor->m_lXDGPopups.remove(*PPOPUP); } \ No newline at end of file diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 59446df4..217fdf57 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -34,7 +34,7 @@ void Events::listener_mapWindow(wl_listener* listener, void* data) { return; } - wl_signal_add(&PWINDOWSURFACE->events.new_subsurface, &PWINDOW->listen_newSubsurfaceWindow); + // wl_signal_add(&PWINDOWSURFACE->events.new_subsurface, &PWINDOW->listen_newSubsurfaceWindow); if (g_pXWaylandManager->shouldBeFloated(PWINDOW)) PWINDOW->m_bIsFloating = true; @@ -131,11 +131,7 @@ void Events::listener_unmapWindow(wl_listener* listener, void* data) { PWINDOW->m_bIsMapped = false; // refocus on a new window - // TODO: investigate. - // If a parent window has focus, any popups (XWayland) will be broken (they will disappear instantly) - // This might be way more sinister in nature and have a problem more deeply - // rooted in the code. - // g_pInputManager->refocus(); + g_pInputManager->refocus(); } void Events::listener_commitWindow(wl_listener* listener, void* data) { @@ -152,25 +148,8 @@ void Events::listener_destroyWindow(wl_listener* listener, void* data) { if (g_pXWaylandManager->getWindowSurface(PWINDOW) == g_pCompositor->m_pLastFocus) g_pCompositor->m_pLastFocus = nullptr; - // TODO: - // We sometimes get invalid pointers here (stack ones) - // this obviously means we tainted wlroots. - // Investigate - g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); - wl_list_remove(&PWINDOW->listen_mapWindow.link); - wl_list_remove(&PWINDOW->listen_unmapWindow.link); - wl_list_remove(&PWINDOW->listen_destroyWindow.link); - wl_list_remove(&PWINDOW->listen_setTitleWindow.link); - wl_list_remove(&PWINDOW->listen_fullscreenWindow.link); - if (PWINDOW->m_bIsX11) { - wl_list_remove(&PWINDOW->listen_activateX11.link); - wl_list_remove(&PWINDOW->listen_configureX11.link); - } else { - wl_list_remove(&PWINDOW->listen_commitWindow.link); - } - g_pCompositor->removeWindowFromVectorSafe(PWINDOW); } @@ -254,31 +233,5 @@ void Events::listener_newXDGSurface(wl_listener* listener, void* data) { wl_signal_add(&XDGSURFACE->events.destroy, &PNEWWINDOW->listen_destroyWindow); wl_signal_add(&XDGSURFACE->toplevel->events.set_title, &PNEWWINDOW->listen_setTitleWindow); wl_signal_add(&XDGSURFACE->toplevel->events.request_fullscreen, &PNEWWINDOW->listen_fullscreenWindow); -} - -// -// Subsurfaces -// - -void createSubsurface(CWindow* pWindow, wlr_subsurface* pSubsurface) { - if (!pWindow || !pSubsurface) - return; - - Debug::log(LOG, "New Window Subsurface %x created", pSubsurface); - - g_pCompositor->m_lSubsurfaces.push_back(SSubsurface()); - const auto PNEWSUBSURFACE = &g_pCompositor->m_lSubsurfaces.back(); - - wl_signal_add(&pSubsurface->events.destroy, &PNEWSUBSURFACE->listen_destroySubsurface); - wl_signal_add(&pSubsurface->events.map, &PNEWSUBSURFACE->listen_mapSubsurface); - wl_signal_add(&pSubsurface->events.unmap, &PNEWSUBSURFACE->listen_unmapSubsurface); - wl_signal_add(&pSubsurface->surface->events.commit, &PNEWSUBSURFACE->listen_commitSubsurface); -} - -void Events::listener_newSubsurfaceWindow(wl_listener* listener, void* data) { - CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_newSubsurfaceWindow); - - const auto PSUBSURFACE = (wlr_subsurface*)data; - - createSubsurface(PWINDOW, PSUBSURFACE); -} + wl_signal_add(&XDGSURFACE->events.new_popup, &PNEWWINDOW->listen_newPopupXDG); +} \ No newline at end of file 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;