From bcb02b9307d09918a11fa377065d7f2c6e506754 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Mon, 21 Mar 2022 16:13:43 +0100 Subject: [PATCH] handle subsurfaces --- CMakeLists.txt | 1 + src/Compositor.hpp | 1 + src/Window.hpp | 1 + src/events/Events.hpp | 10 +++++ src/events/Layers.cpp | 89 ++++++++++++++++++++++++++------------- src/events/Windows.cpp | 69 ++++++++++++++++++++++++++++++ src/helpers/Monitor.hpp | 1 + src/helpers/WLClasses.hpp | 25 ++++++++++- src/includes.hpp | 2 + src/render/Renderer.cpp | 47 +++++++++++++++++++++ src/render/Renderer.hpp | 1 + 11 files changed, 215 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ffa8c05..c1d0cd76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ target_link_libraries(Hyprland PkgConfig::deps) target_link_libraries(Hyprland wlroots + pixman-1 ${CMAKE_THREAD_LIBS_INIT} ) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index fbc49cf4..0b520f22 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -53,6 +53,7 @@ public: std::list m_lLayerPopups; std::list m_lXDGPopups; std::list m_lWorkspaces; + std::list m_lSubsurfaces; void startCompositor(); diff --git a/src/Window.hpp b/src/Window.hpp index 116ffb20..9aed5904 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -14,6 +14,7 @@ public: DYNLISTENER(setTitleWindow); DYNLISTENER(fullscreenWindow); DYNLISTENER(newPopupXDG); + DYNLISTENER(newSubsurfaceWindow); union { wlr_xdg_surface* xdg; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 9ac805fe..4313d8d1 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -13,6 +13,13 @@ namespace Events { LISTENER(unmapLayerSurface); LISTENER(commitLayerSurface); + // Subsurfaces + LISTENER(newSubsurface); + LISTENER(mapSubsurface); + LISTENER(unmapSubsurface); + LISTENER(destroySubsurface); + LISTENER(commitSubsurface); + // Popups LISTENER(newPopup); LISTENER(newPopupFromPopup); @@ -41,6 +48,9 @@ namespace Events { LISTENER(activateX11); LISTENER(configureX11); + // Window subsurfaces + LISTENER(newSubsurfaceWindow); + // Input events LISTENER(mouseMove); LISTENER(mouseMoveAbsolute); diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp index cffccd9b..d6e83073 100644 --- a/src/events/Layers.cpp +++ b/src/events/Layers.cpp @@ -44,6 +44,7 @@ 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; WLRLAYERSURFACE->data = layerSurface; @@ -144,44 +145,72 @@ void Events::listener_commitLayerSurface(wl_listener* listener, void* data) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID); } -void Events::listener_surfaceXWayland(wl_listener* listener, void* data) { - const auto XWSURFACE = (wlr_xwayland_surface*)data; +// +// Subsurfaces +// - g_pCompositor->m_lWindows.push_back(CWindow()); - const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back(); +void createSubsurface(wlr_subsurface* pSubSurface, SLayerSurface* pLayerSurface) { + if (!pSubSurface || !pLayerSurface) + return; - PNEWWINDOW->m_uSurface.xwayland = XWSURFACE; - PNEWWINDOW->m_iX11Type = XWSURFACE->override_redirect ? 2 : 1; - PNEWWINDOW->m_bIsX11 = true; + g_pCompositor->m_lSubsurfaces.push_back(SSubsurface()); + const auto PNEWSUBSURFACE = &g_pCompositor->m_lSubsurfaces.back(); - wl_signal_add(&XWSURFACE->events.map, &PNEWWINDOW->listen_mapWindow); - wl_signal_add(&XWSURFACE->events.unmap, &PNEWWINDOW->listen_unmapWindow); - wl_signal_add(&XWSURFACE->events.request_activate, &PNEWWINDOW->listen_activateX11); - wl_signal_add(&XWSURFACE->events.request_configure, &PNEWWINDOW->listen_configureX11); - wl_signal_add(&XWSURFACE->events.set_title, &PNEWWINDOW->listen_setTitleWindow); - wl_signal_add(&XWSURFACE->events.destroy, &PNEWWINDOW->listen_destroyWindow); - wl_signal_add(&XWSURFACE->events.request_fullscreen, &PNEWWINDOW->listen_fullscreenWindow); + PNEWSUBSURFACE->subsurface = pSubSurface; + PNEWSUBSURFACE->pParentSurface = pLayerSurface; - Debug::log(LOG, "New XWayland Surface created."); + 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 Events::listener_newXDGSurface(wl_listener* listener, void* data) { - // A window got opened - const auto XDGSURFACE = (wlr_xdg_surface*)data; +void damageSubsurface(SSubsurface* subSurface, bool all = false) { + if (!subSurface->pParentSurface->layerSurface->output) + return; - if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) - return; // TODO: handle? + const auto PMONITOR = g_pCompositor->getMonitorFromOutput(subSurface->pParentSurface->layerSurface->output); - g_pCompositor->m_lWindows.push_back(CWindow()); - const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back(); - PNEWWINDOW->m_uSurface.xdg = XDGSURFACE; + if (!PMONITOR) + return; // wut? - wl_signal_add(&XDGSURFACE->surface->events.commit, &PNEWWINDOW->listen_commitWindow); - wl_signal_add(&XDGSURFACE->events.map, &PNEWWINDOW->listen_mapWindow); - wl_signal_add(&XDGSURFACE->events.unmap, &PNEWWINDOW->listen_unmapWindow); - 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); + int x = subSurface->subsurface->current.x + subSurface->pParentSurface->geometry.x; + int y = subSurface->subsurface->current.y + subSurface->pParentSurface->geometry.y; - Debug::log(LOG, "New XDG Surface created."); + 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); + + damageSubsurface(subsurface, true); +} + +void Events::listener_unmapSubsurface(wl_listener* listener, void* data) { + SSubsurface* subsurface = wl_container_of(listener, subsurface, listen_unmapSubsurface); + + 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); + + 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); } \ No newline at end of file diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 2c89301c..bf18fb20 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -102,4 +102,73 @@ void Events::listener_configureX11(wl_listener* listener, void* data) { // TODO: ignore if tiled? wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height); +} + +void Events::listener_surfaceXWayland(wl_listener* listener, void* data) { + const auto XWSURFACE = (wlr_xwayland_surface*)data; + + g_pCompositor->m_lWindows.push_back(CWindow()); + const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back(); + + PNEWWINDOW->m_uSurface.xwayland = XWSURFACE; + PNEWWINDOW->m_iX11Type = XWSURFACE->override_redirect ? 2 : 1; + PNEWWINDOW->m_bIsX11 = true; + + wl_signal_add(&XWSURFACE->events.map, &PNEWWINDOW->listen_mapWindow); + wl_signal_add(&XWSURFACE->events.unmap, &PNEWWINDOW->listen_unmapWindow); + wl_signal_add(&XWSURFACE->events.request_activate, &PNEWWINDOW->listen_activateX11); + wl_signal_add(&XWSURFACE->events.request_configure, &PNEWWINDOW->listen_configureX11); + wl_signal_add(&XWSURFACE->events.set_title, &PNEWWINDOW->listen_setTitleWindow); + wl_signal_add(&XWSURFACE->events.destroy, &PNEWWINDOW->listen_destroyWindow); + wl_signal_add(&XWSURFACE->events.request_fullscreen, &PNEWWINDOW->listen_fullscreenWindow); + wl_signal_add(&XWSURFACE->surface->events.new_subsurface, &PNEWWINDOW->listen_newSubsurfaceWindow); + + Debug::log(LOG, "New XWayland Surface created."); +} + +void Events::listener_newXDGSurface(wl_listener* listener, void* data) { + // A window got opened + const auto XDGSURFACE = (wlr_xdg_surface*)data; + + if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) + return; // TODO: handle? + + g_pCompositor->m_lWindows.push_back(CWindow()); + const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back(); + PNEWWINDOW->m_uSurface.xdg = XDGSURFACE; + + wl_signal_add(&XDGSURFACE->surface->events.commit, &PNEWWINDOW->listen_commitWindow); + wl_signal_add(&XDGSURFACE->events.map, &PNEWWINDOW->listen_mapWindow); + wl_signal_add(&XDGSURFACE->events.unmap, &PNEWWINDOW->listen_unmapWindow); + 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); + wl_signal_add(&XDGSURFACE->surface->events.new_subsurface, &PNEWWINDOW->listen_newSubsurfaceWindow); + + Debug::log(LOG, "New XDG Surface created."); +} + +// +// Subsurfaces +// + +void createSubsurface(CWindow* pWindow, wlr_subsurface* pSubsurface) { + if (!pWindow || !pSubsurface) + return; + + 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); } \ No newline at end of file diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 0977b1f8..b3f10893 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -23,6 +23,7 @@ struct SMonitor { // WLR stuff wlr_output* output = nullptr; float refreshRate = 60; + wlr_output_damage* damage = nullptr; // Double-linked list because we need to have constant mem addresses for signals // We have to store pointers and use raw new/delete because they might be moved between them diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 8d7dcede..c37bf5a5 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -14,6 +14,7 @@ struct SLayerSurface { DYNLISTENER(unmapLayerSurface); DYNLISTENER(commitLayerSurface); DYNLISTENER(newPopup); + DYNLISTENER(newSubsurface); wlr_box geometry; zwlr_layer_shell_v1_layer layer; @@ -27,11 +28,31 @@ 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; - int x; - int y; + int x, y; + + // for iters + void* data = nullptr; + wlr_surface* surface = nullptr; + int w, h; }; struct SKeyboard { diff --git a/src/includes.hpp b/src/includes.hpp index c29644de..593e363d 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -66,8 +66,10 @@ extern "C" { #include #include #include +#include #include #include +#include #include #include } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6800d586..262b3d72 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -263,4 +263,51 @@ void CHyprRenderer::drawBorderForWindow(CWindow* pWindow, SMonitor* pMonitor) { // right border.x = correctPos.x + pWindow->m_vRealSize.x; wlr_render_rect(g_pCompositor->m_sWLRRenderer, &border, BORDERWLRCOL, pMonitor->output->transform_matrix); +} + +void damageSurfaceIter(struct wlr_surface* surface, int x, int y, void* data) { + auto* renderdata = (SRenderData*)data; + bool entire = (bool*)renderdata->data; + + wlr_box box = {.x = renderdata->x, .y = renderdata->y, .width = renderdata->w, .height = renderdata->h}; + scaleBox(&box, renderdata->output->scale); + + pixman_region32_t damageRegion; + pixman_region32_init(&damageRegion); + wlr_surface_get_effective_damage(renderdata->surface, &damageRegion); + wlr_region_scale(&damageRegion, &damageRegion, renderdata->output->scale); + + if (std::ceil(renderdata->output->scale) > renderdata->surface->current.scale) { + wlr_region_expand(&damageRegion, &damageRegion, std::ceil(renderdata->output->scale) - renderdata->surface->current.scale); + } + + const auto PMONITOR = g_pCompositor->getMonitorFromOutput(renderdata->output); + + pixman_region32_translate(&damageRegion, box.x, box.y); + wlr_output_damage_add(PMONITOR->damage, &damageRegion); + pixman_region32_fini(&damageRegion); + + if (entire) + wlr_output_damage_add_box(PMONITOR->damage, &box); + + if (!wl_list_empty(&surface->current.frame_callback_list)) { + wlr_output_schedule_frame(renderdata->output); + } +} + +void CHyprRenderer::damageSurface(SMonitor* pMonitor, double x, double y, wlr_surface* pSurface, void* data) { + if (!pSurface || !pMonitor) + return; // wut? + + SRenderData renderData = { + .output = pMonitor->output, + .x = x, + .y = y, + .data = data, + .surface = pSurface, + .w = pSurface->current.width, + .h = pSurface->current.height + }; + + wlr_surface_for_each_surface(pSurface, damageSurfaceIter, &renderData); } \ No newline at end of file diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b6172ce8..2f9995e2 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -11,6 +11,7 @@ public: void renderAllClientsForMonitor(const int&, timespec*); void outputMgrApplyTest(wlr_output_configuration_v1*, bool); void arrangeLayersForMonitor(const int&); + void damageSurface(SMonitor*, double, double, wlr_surface*, void*); private: void arrangeLayerArray(SMonitor*, const std::list&);