diff --git a/CMakeLists.txt b/CMakeLists.txt index 513f06bb..eb766005 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.5 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.6 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) file(GLOB_RECURSE SRCFILES "src/*.cpp") @@ -251,7 +251,6 @@ target_link_libraries(Hyprland uuid ) -protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) @@ -268,6 +267,7 @@ protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true) +protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) protocolNew("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false) diff --git a/protocols/meson.build b/protocols/meson.build index 345b47ee..4206b56a 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -27,7 +27,6 @@ protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], - ['wlr-layer-shell-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] @@ -42,6 +41,7 @@ new_protocols = [ ['wlr-virtual-pointer-unstable-v1.xml'], ['wlr-output-management-unstable-v1.xml'], ['kde-server-decoration.xml'], + ['wlr-layer-shell-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], diff --git a/protocols/wlr-layer-shell-unstable-v1.xml b/protocols/wlr-layer-shell-unstable-v1.xml index d62fd51e..e9f27e4f 100644 --- a/protocols/wlr-layer-shell-unstable-v1.xml +++ b/protocols/wlr-layer-shell-unstable-v1.xml @@ -25,7 +25,7 @@ THIS SOFTWARE. - + Clients can use this interface to assign the surface_layer role to wl_surfaces. Such surfaces are assigned to a "layer" of the output and @@ -100,7 +100,7 @@ - + An interface that may be implemented by a wl_surface, for surfaces that are designed to be rendered as a layer of a stacked desktop-like @@ -367,6 +367,7 @@ + @@ -386,5 +387,21 @@ + + + + + + Requests an edge for the exclusive zone to apply. The exclusive + edge will be automatically deduced from anchor points when possible, + but when the surface is anchored to a corner, it will be necessary + to set it explicitly to disambiguate, as it is not possible to deduce + which one of the two corner edges should be used. + + The edge must be one the surface is anchored to, otherwise the + invalid_exclusive_edge protocol error will be raised. + + + diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 90ef2b66..da2b643c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -16,6 +16,7 @@ #include "helpers/VarList.hpp" #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" +#include "protocols/LayerShell.hpp" #include "desktop/LayerSurface.hpp" #include @@ -234,8 +235,6 @@ void CCompositor::initServer() { m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend); - m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4); - m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend); if (!m_sWRLDRMLeaseMgr) { Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager"); @@ -271,7 +270,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sSeat.seat->events.start_drag, &Events::listen_startDrag, &m_sSeat, "Seat"); addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); addWLSignal(&m_sSeat.seat->events.request_set_primary_selection, &Events::listen_requestSetPrimarySel, &m_sSeat, "Seat"); - addWLSignal(&m_sWLRLayerShell->events.new_surface, &Events::listen_newLayerSurface, m_sWLRLayerShell, "LayerShell"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); if (m_sWRLDRMLeaseMgr) @@ -291,7 +289,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_startDrag); removeWLSignal(&Events::listen_requestSetSel); removeWLSignal(&Events::listen_requestSetPrimarySel); - removeWLSignal(&Events::listen_newLayerSurface); removeWLSignal(&Events::listen_RendererDestroy); if (m_sWRLDRMLeaseMgr) @@ -1088,17 +1085,15 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto& ls : lsl | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) + if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) continue; - auto SURFACEAT = wlr_layer_surface_v1_popup_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y); + auto SURFACEAT = ls->popupHead->at(pos, true); if (SURFACEAT) { - if (!pixman_region32_not_empty(&SURFACEAT->input_region)) - continue; - - *ppLayerSurfaceFound = ls; - return SURFACEAT; + *ppLayerSurfaceFound = ls.lock(); + *sCoords = pos - SURFACEAT->coordsGlobal(); + return SURFACEAT->m_sWLSurface.wlr(); } } } @@ -1106,7 +1101,7 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito return nullptr; } -wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { +wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& ls : *layerSurfaces | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; @@ -1117,7 +1112,7 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector< if (!pixman_region32_not_empty(&SURFACEAT->input_region)) continue; - *ppLayerSurfaceFound = ls; + *ppLayerSurfaceFound = ls.lock(); return SURFACEAT; } } @@ -1355,7 +1350,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { void CCompositor::cleanupFadingOut(const int& monid) { for (auto& ww : m_vWindowsFadingOut) { - const auto w = ww.lock(); + auto w = ww.lock(); if (w->m_iMonitorID != (long unsigned int)monid) continue; @@ -1369,6 +1364,8 @@ void CCompositor::cleanupFadingOut(const int& monid) { removeWindowFromVectorSafe(w); + w.reset(); + Debug::log(LOG, "Cleanup: destroyed a window"); return; } @@ -1398,6 +1395,9 @@ void CCompositor::cleanupFadingOut(const int& monid) { } std::erase_if(m_vSurfacesFadingOut, [ls](const auto& el) { return el.lock() == ls; }); + std::erase_if(m_vLayers, [ls](const auto& el) { return el == ls; }); + + ls.reset(); Debug::log(LOG, "Cleanup: destroyed a layersurface"); @@ -2414,19 +2414,6 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { setActiveMonitor(PMONITORNEW); } -PHLLS CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) { - for (auto& m : m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { - if (ls->layerSurface == pLS) - return ls; - } - } - } - - return nullptr; -} - void CCompositor::closeWindow(PHLWINDOW pWindow) { if (pWindow && validMapped(pWindow)) { g_pXWaylandManager->sendCloseWindow(pWindow); @@ -2436,28 +2423,24 @@ void CCompositor::closeWindow(PHLWINDOW pWindow) { PHLLS CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) { std::pair result = {pSurface, false}; - for (auto& m : m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { - if (ls->layerSurface && ls->layerSurface->surface == pSurface) - return ls; + for (auto& ls : m_vLayers) { + if (ls->layerSurface && ls->layerSurface->surface == pSurface) + return ls; - static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void { - if (surf == ((std::pair*)data)->first) { - *(bool*)data = true; - return; - } - }; - - if (!ls->layerSurface || !ls->mapped) - continue; - - wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result); - - if (result.second) - return ls; + static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void { + if (surf == ((std::pair*)data)->first) { + *(bool*)data = true; + return; } - } + }; + + if (!ls->layerSurface || !ls->mapped) + continue; + + wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result); + + if (result.second) + return ls; } return nullptr; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 96557b8d..9659df5c 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -51,7 +51,6 @@ class CCompositor { wlr_data_device_manager* m_sWLRDataDevMgr; wlr_drm* m_sWRLDRM; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_layer_shell_v1* m_sWLRLayerShell; wlr_xdg_shell* m_sWLRXDGShell; wlr_presentation* m_sWLRPresentation; wlr_egl* m_sWLREGL; @@ -71,6 +70,7 @@ class CCompositor { std::vector> m_vMonitors; std::vector> m_vRealMonitors; // for all monitors, even those turned off std::vector m_vWindows; + std::vector m_vLayers; std::vector m_vWorkspaces; std::vector m_vWindowsFadingOut; std::vector m_vSurfacesFadingOut; @@ -112,7 +112,7 @@ class CCompositor { void focusSurface(wlr_surface*, PHLWINDOW pWindowOwner = nullptr); bool monitorExists(CMonitor*); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); - wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*); + wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*); wlr_surface* vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); wlr_surface* vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, wlr_surface*); @@ -162,7 +162,6 @@ class CCompositor { void addToFadingOutSafe(PHLWINDOW); PHLWINDOW getWindowByRegex(const std::string&); void warpCursorTo(const Vector2D&, bool force = false); - PHLLS getLayerSurfaceFromWlr(wlr_layer_surface_v1*); PHLLS getLayerSurfaceFromSurface(wlr_surface*); void closeWindow(PHLWINDOW); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 135a6a94..7804a511 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -4,6 +4,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "config/ConfigDataValues.hpp" #include "helpers/VarList.hpp" +#include "../protocols/LayerShell.hpp" #include #include @@ -1204,7 +1205,7 @@ std::vector CConfigManager::getMatchingRules(PHLLS pLS) { } else { std::regex NSCHECK(lr.targetNamespace); - if (!pLS->layerSurface->_namespace || !std::regex_search(pLS->layerSurface->_namespace, NSCHECK)) + if (!std::regex_search(pLS->layerSurface->layerNamespace, NSCHECK)) continue; } @@ -1212,8 +1213,8 @@ std::vector CConfigManager::getMatchingRules(PHLLS pLS) { returns.push_back(lr); } - if (pLS->layerSurface->_namespace && shouldBlurLS(pLS->layerSurface->_namespace)) - returns.push_back({pLS->layerSurface->_namespace, "blur"}); + if (shouldBlurLS(pLS->layerSurface->layerNamespace)) + returns.push_back({pLS->layerSurface->layerNamespace, "blur"}); return returns; } diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index aeaf1aa8..c9750dc9 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -1,81 +1,29 @@ #include "LayerSurface.hpp" #include "../Compositor.hpp" #include "../events/Events.hpp" +#include "../protocols/LayerShell.hpp" -void Events::listener_newLayerSurface(wl_listener* listener, void* data) { - const auto WLRLAYERSURFACE = (wlr_layer_surface_v1*)data; +PHLLS CLayerSurface::create(SP resource) { + PHLLS pLS = SP(new CLayerSurface(resource)); - if (!WLRLAYERSURFACE->output) { - const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); + CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor); - if (!PMONITOR) { - Debug::log(ERR, "No monitor at cursor on new layer without a monitor. Ignoring."); - wlr_layer_surface_v1_destroy(WLRLAYERSURFACE); - return; - } - - Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor {}", PMONITOR->szName); - - WLRLAYERSURFACE->output = PMONITOR->output; + if (!pMonitor) { + Debug::log(ERR, "New LS has no monitor??"); + return pLS; } - auto PMONITOR = g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output); - - if (!WLRLAYERSURFACE->output || !PMONITOR || PMONITOR->pMirrorOf) { - PMONITOR = g_pCompositor->m_vMonitors.front().get(); - WLRLAYERSURFACE->output = PMONITOR->output; // TODO: current mon - } - - const auto PLS = PMONITOR->m_aLayerSurfaceLayers[WLRLAYERSURFACE->pending.layer].emplace_back(CLayerSurface::create(WLRLAYERSURFACE)); - - Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)WLRLAYERSURFACE, WLRLAYERSURFACE->_namespace, (int)PLS->layer, PMONITOR->szName); -} - -static void onCommit(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onCommit(); -} - -static void onMap(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onMap(); -} - -static void onUnmap(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onUnmap(); -} - -static void onDestroy(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onDestroy(); -} - -// IMPL - -PHLLS CLayerSurface::create(wlr_layer_surface_v1* pWLRLS) { - PHLLS pLS = SP(new CLayerSurface); - - auto PMONITOR = g_pCompositor->getMonitorFromOutput(pWLRLS->output); + if (pMonitor->pMirrorOf) + pMonitor = g_pCompositor->m_vMonitors.front().get(); pLS->self = pLS; - pLS->szNamespace = pWLRLS->_namespace; + pLS->szNamespace = resource->layerNamespace; - pLS->hyprListener_commitLayerSurface.initCallback(&pWLRLS->surface->events.commit, ::onCommit, pLS.get(), "layerSurface"); - pLS->hyprListener_destroyLayerSurface.initCallback(&pWLRLS->events.destroy, ::onDestroy, pLS.get(), "layerSurface"); - pLS->hyprListener_mapLayerSurface.initCallback(&pWLRLS->surface->events.map, ::onMap, pLS.get(), "layerSurface"); - pLS->hyprListener_unmapLayerSurface.initCallback(&pWLRLS->surface->events.unmap, ::onUnmap, pLS.get(), "layerSurface"); - - pLS->layerSurface = pWLRLS; - pLS->layer = pWLRLS->current.layer; - pWLRLS->data = pLS.get(); - pLS->monitorID = PMONITOR->ID; - pLS->popupHead = std::make_unique(pLS); + pLS->layer = resource->current.layer; + pLS->popupHead = std::make_unique(pLS); + pLS->monitorID = pMonitor->ID; + pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); @@ -90,7 +38,9 @@ PHLLS CLayerSurface::create(wlr_layer_surface_v1* pWLRLS) { pLS->alpha.setValueAndWarp(0.f); - pLS->surface.assign(pWLRLS->surface, pLS); + pLS->surface.assign(resource->surface, pLS); + + Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); return pLS; } @@ -102,8 +52,11 @@ void CLayerSurface::registerCallbacks() { }); } -CLayerSurface::CLayerSurface() { - ; +CLayerSurface::CLayerSurface(SP resource_) : layerSurface(resource_) { + listeners.commit = layerSurface->events.commit.registerListener([this](std::any d) { onCommit(); }); + listeners.map = layerSurface->events.map.registerListener([this](std::any d) { onMap(); }); + listeners.unmap = layerSurface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); + listeners.destroy = layerSurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); } CLayerSurface::~CLayerSurface() { @@ -139,11 +92,6 @@ void CLayerSurface::onDestroy() { noProcess = true; - hyprListener_commitLayerSurface.removeCallback(); - hyprListener_destroyLayerSurface.removeCallback(); - hyprListener_mapLayerSurface.removeCallback(); - hyprListener_unmapLayerSurface.removeCallback(); - // rearrange to fix the reserved areas if (PMONITOR) { g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); @@ -155,7 +103,7 @@ void CLayerSurface::onDestroy() { } readyToDelete = true; - layerSurface = nullptr; + layerSurface.reset(); surface.unassign(); } @@ -163,7 +111,7 @@ void CLayerSurface::onMap() { Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); mapped = true; - keyboardExclusive = layerSurface->current.keyboard_interactive; + keyboardExclusive = layerSurface->current.interactivity; // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -173,28 +121,16 @@ void CLayerSurface::onMap() { applyRules(); - if ((uint64_t)monitorID != PMONITOR->ID) { - const auto POLDMON = g_pCompositor->getMonitorFromID(monitorID); - for (auto it = POLDMON->m_aLayerSurfaceLayers[layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layer].end(); it++) { - if (*it == self) { - PMONITOR->m_aLayerSurfaceLayers[layer].emplace_back(std::move(*it)); - POLDMON->m_aLayerSurfaceLayers[layer].erase(it); - break; - } - } - monitorID = PMONITOR->ID; - PMONITOR->scheduledRecalc = true; - g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID); - } + PMONITOR->scheduledRecalc = true; g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); wlr_surface_send_enter(surface.wlr(), PMONITOR->output); - if (layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) g_pInputManager->m_dExclusiveLSes.push_back(self); - const bool GRABSFOCUS = layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && + const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && // don't focus if constrained (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()); @@ -229,7 +165,7 @@ void CLayerSurface::onMap() { void CLayerSurface::onUnmap() { Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface); - g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layerSurface->_namespace ? layerSurface->_namespace : "")}); + g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace}); EMIT_HOOK_EVENT("closeLayer", self.lock()); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); @@ -257,7 +193,7 @@ void CLayerSurface::onUnmap() { g_pCompositor->addToFadingOutSafe(self.lock()); - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layerSurface->output); + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layerSurface->surface; @@ -306,10 +242,10 @@ void CLayerSurface::onUnmap() { } void CLayerSurface::onCommit() { - if (!layerSurface || !layerSurface->output) + if (!layerSurface) return; - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layerSurface->output); + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); if (!PMONITOR) return; @@ -320,25 +256,8 @@ void CLayerSurface::onCommit() { CBox geomFixed = {geometry.x, geometry.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); - // fix if it changed its mon - if ((uint64_t)monitorID != PMONITOR->ID) { - const auto POLDMON = g_pCompositor->getMonitorFromID(monitorID); - - for (auto it = POLDMON->m_aLayerSurfaceLayers[layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layer].end(); it++) { - if (*it == self) { - PMONITOR->m_aLayerSurfaceLayers[layer].emplace_back(std::move(*it)); - POLDMON->m_aLayerSurfaceLayers[layer].erase(it); - break; - } - } - - monitorID = PMONITOR->ID; - PMONITOR->scheduledRecalc = true; - g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID); - } - if (layerSurface->current.committed != 0) { - if (layer != layerSurface->current.layer) { + if (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) { for (auto it = PMONITOR->m_aLayerSurfaceLayers[layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layer].end(); it++) { if (*it == self) { @@ -383,7 +302,7 @@ void CLayerSurface::onCommit() { realSize.setValueAndWarp(geometry.size()); } - if (layerSurface->current.keyboard_interactive && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained + if (layerSurface->current.interactivity && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained && !keyboardExclusive && mapped) { g_pCompositor->focusSurface(layerSurface->surface); @@ -391,11 +310,11 @@ void CLayerSurface::onCommit() { wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layerSurface->surface, LOCAL.x, LOCAL.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y); g_pInputManager->m_bEmptyFocusCursorSet = false; - } else if (!layerSurface->current.keyboard_interactive && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { + } else if (!layerSurface->current.interactivity && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { g_pInputManager->refocus(); } - keyboardExclusive = layerSurface->current.keyboard_interactive; + keyboardExclusive = layerSurface->current.interactivity; g_pHyprRenderer->damageSurface(layerSurface->surface, position.x, position.y); @@ -582,8 +501,7 @@ int CLayerSurface::popupsCount() { if (!layerSurface || !mapped || fadingOut) return 0; - int no = 0; - wlr_layer_surface_v1_for_each_popup_surface( - layerSurface, [](wlr_surface* s, int x, int y, void* data) { *(int*)data += 1; }, &no); + int no = -1; // we have one dummy + popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); return no; } \ No newline at end of file diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index f1540be5..d60a6dd0 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -4,19 +4,20 @@ #include "../defines.hpp" #include "WLSurface.hpp" #include "../helpers/AnimatedVariable.hpp" -#include "wlr-layer-shell-unstable-v1-protocol.h" struct SLayerRule { std::string targetNamespace = ""; std::string rule = ""; }; +class CLayerShellResource; + class CLayerSurface { public: - static PHLLS create(wlr_layer_surface_v1*); + static PHLLS create(SP); private: - CLayerSurface(); + CLayerSurface(SP); public: ~CLayerSurface(); @@ -30,7 +31,7 @@ class CLayerSurface { CAnimatedVariable realSize; CAnimatedVariable alpha; - wlr_layer_surface_v1* layerSurface; + WP layerSurface; wl_list link; bool keyboardExclusive = false; @@ -38,6 +39,7 @@ class CLayerSurface { CWLSurface surface; bool mapped = false; + uint32_t layer = 0; int monitorID = -1; @@ -55,13 +57,12 @@ class CLayerSurface { std::optional animationStyle; - zwlr_layer_shell_v1_layer layer; - PHLLSREF self; CBox geometry = {0, 0, 0, 0}; Vector2D position; std::string szNamespace = ""; + std::unique_ptr popupHead; void onDestroy(); void onMap(); @@ -69,12 +70,12 @@ class CLayerSurface { void onCommit(); private: - std::unique_ptr popupHead; - - DYNLISTENER(destroyLayerSurface); - DYNLISTENER(mapLayerSurface); - DYNLISTENER(unmapLayerSurface); - DYNLISTENER(commitLayerSurface); + struct { + CHyprSignalListener destroy; + CHyprSignalListener map; + CHyprSignalListener unmap; + CHyprSignalListener commit; + } listeners; void registerCallbacks(); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 73a29560..f1517083 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -1,6 +1,8 @@ #include "Popup.hpp" #include "../config/ConfigValue.hpp" #include "../Compositor.hpp" +#include "../protocols/LayerShell.hpp" +#include CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { initAllSignals(); @@ -72,7 +74,7 @@ void CPopup::initAllSignals() { if (!m_pWindowOwner.expired()) hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head"); else if (!m_pLayerOwner.expired()) - hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head"); + listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast(d)); }); else ASSERT(false); @@ -278,3 +280,46 @@ bool CPopup::visible() { return false; } + +void CPopup::bfHelper(std::vector nodes, std::function fn, void* data) { + for (auto& n : nodes) { + fn(n, data); + } + + std::vector nodes2; + + for (auto& n : nodes) { + for (auto& c : n->m_vChildren) { + nodes2.push_back(c.get()); + } + } + + bfHelper(nodes2, fn, data); +} + +void CPopup::breadthfirst(std::function fn, void* data) { + std::vector popups; + popups.push_back(this); +} + +CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { + std::vector popups; + breadthfirst([](CPopup* popup, void* data) { ((std::vector*)data)->push_back(popup); }, &popups); + + for (auto& p : popups | std::views::reverse) { + if (!p->m_pWLR) + continue; + + if (!allowsInput) { + const auto BOX = CBox{p->coordsGlobal(), p->size()}; + if (BOX.containsPoint(globalCoords)) + return p; + } else { + const auto REGION = CRegion{&m_sWLSurface.wlr()->current.input}.translate(p->coordsGlobal()); + if (REGION.containsPoint(globalCoords)) + return p; + } + } + + return nullptr; +} diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index cadbf244..6aa7ce61 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -3,6 +3,7 @@ #include #include #include "Subsurface.hpp" +#include "../helpers/signal/Listener.hpp" class CPopup { public: @@ -15,22 +16,27 @@ class CPopup { ~CPopup(); - Vector2D coordsRelativeToParent(); - Vector2D coordsGlobal(); + Vector2D coordsRelativeToParent(); + Vector2D coordsGlobal(); - Vector2D size(); + Vector2D size(); - void onNewPopup(wlr_xdg_popup* popup); - void onDestroy(); - void onMap(); - void onUnmap(); - void onCommit(bool ignoreSiblings = false); - void onReposition(); + void onNewPopup(wlr_xdg_popup* popup); + void onDestroy(); + void onMap(); + void onUnmap(); + void onCommit(bool ignoreSiblings = false); + void onReposition(); - void recheckTree(); + void recheckTree(); - bool visible(); + bool visible(); + // will also loop over this node + void breadthfirst(std::function fn, void* data); + CPopup* at(const Vector2D& globalCoords, bool allowsInput = false); + + // CWLSurface m_sWLSurface; private: @@ -62,11 +68,16 @@ class CPopup { DYNLISTENER(commitPopup); DYNLISTENER(repositionPopup); - void initAllSignals(); - void unconstrain(); - void recheckChildrenRecursive(); - void sendScale(); + struct { + CHyprSignalListener newPopup; + } listeners; - Vector2D localToGlobal(const Vector2D& rel); - Vector2D t1ParentCoords(); + void initAllSignals(); + void unconstrain(); + void recheckChildrenRecursive(); + void sendScale(); + + Vector2D localToGlobal(const Vector2D& rel); + Vector2D t1ParentCoords(); + static void bfHelper(std::vector nodes, std::function fn, void* data); }; \ No newline at end of file diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 221348ff..4ccf8e41 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -6,6 +6,7 @@ #include "../managers/TokenManager.hpp" #include "../render/Renderer.hpp" #include "../config/ConfigValue.hpp" +#include "../protocols/LayerShell.hpp" // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // @@ -481,7 +482,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // check LS focus grab const auto PFORCEFOCUS = g_pCompositor->getForceFocus(); const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); - if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive) + if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) PWINDOW->m_bNoInitialFocus = true; if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) { if (*PNEWTAKESOVERFS == 0) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index fa68655f..31d8d22f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -4,6 +4,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" #include "../devices/ITouch.hpp" +#include "../protocols/LayerShell.hpp" int ratHandler(void* data) { g_pHyprRenderer->renderMonitor((CMonitor*)data); @@ -254,7 +255,7 @@ void CMonitor::onDisconnect(bool destroy) { for (size_t i = 0; i < 4; ++i) { for (auto& ls : m_aLayerSurfaceLayers[i]) { if (ls->layerSurface && !ls->fadingOut) - wlr_layer_surface_v1_destroy(ls->layerSurface); + ls->layerSurface->sendClosed(); } m_aLayerSurfaceLayers[i].clear(); } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2d49aeb3..48bb67e5 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -140,7 +140,7 @@ class CMonitor { CSignal modeChanged; } events; - std::array, 4> m_aLayerSurfaceLayers; + std::array, 4> m_aLayerSurfaceLayers; DYNLISTENER(monitorFrame); DYNLISTENER(monitorDestroy); diff --git a/src/includes.hpp b/src/includes.hpp index 080dbd4e..c16fe777 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -48,7 +48,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 21c1055f..f8cb0184 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -224,7 +224,7 @@ void CAnimationManager::tick() { g_pHyprRenderer->damageWindow(w); } } else if (PLAYER) { - if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) + if (PLAYER->layer <= 1) g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // some fucking layers miss 1 pixel??? diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 60fde1aa..73f33a20 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -26,6 +26,7 @@ #include "../protocols/ServerDecorationKDE.hpp" #include "../protocols/FocusGrab.hpp" #include "../protocols/Tablet.hpp" +#include "../protocols/LayerShell.hpp" CProtocolManager::CProtocolManager() { @@ -55,6 +56,7 @@ CProtocolManager::CProtocolManager() { PROTO::serverDecorationKDE = std::make_unique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); PROTO::focusGrab = std::make_unique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); PROTO::tablet = std::make_unique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); + PROTO::layerShell = std::make_unique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 8d67760d..76f76126 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -13,6 +13,7 @@ #include "../../protocols/InputMethodV2.hpp" #include "../../protocols/VirtualKeyboard.hpp" #include "../../protocols/VirtualPointer.hpp" +#include "../../protocols/LayerShell.hpp" #include "../../devices/Mouse.hpp" #include "../../devices/VirtualPointer.hpp" @@ -399,7 +400,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!refocus && g_pCompositor->m_pLastFocus) { const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); - if (PLS && PLS->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + if (PLS && PLS->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) allowKeyboardRefocus = false; } @@ -479,7 +480,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { unsetCursorImage(); } - if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 && + if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 && allowKeyboardRefocus) { g_pCompositor->focusSurface(foundSurface); } diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 63adc8ca..44623671 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -37,7 +37,7 @@ void CInputManager::beginWorkspaceSwipe() { m_sActiveSwipe.speedPoints = 0; if (PWORKSPACE->m_bHasFullscreenWindow) { - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = 1.f; } } @@ -193,7 +193,7 @@ void CInputManager::endWorkspaceSwipe() { g_pInputManager->refocus(); // apply alpha - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f; } } diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 60d85aa6..4a6484c2 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -33,7 +33,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { if (m_sActiveSwipe.pWorkspaceBegin) { return; // TODO: Don't swipe if you touched a floating window. - } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)) { + } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= 1)) { const auto PWORKSPACE = PMONITOR->activeWorkspace; const bool VERTANIMS = PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp new file mode 100644 index 00000000..ced765fd --- /dev/null +++ b/src/protocols/LayerShell.cpp @@ -0,0 +1,224 @@ +#include "LayerShell.hpp" +#include "../Compositor.hpp" + +#define LOGM PROTO::layerShell->protoLog + +void CLayerShellResource::SState::reset() { + anchor = 0; + exclusive = 0; + interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; + layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; + exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + desiredSize = {}; + margin = {0, 0, 0, 0}; +} + +CLayerShellResource::CLayerShellResource(SP resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) : + layerNamespace(namespace_), surface(surf_), resource(resource_) { + if (!good()) + return; + + current.layer = layer; + monitor = pMonitor ? pMonitor->szName : ""; + + resource->setDestroy([this](CZwlrLayerSurfaceV1* r) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }); + resource->setOnDestroy([this](CZwlrLayerSurfaceV1* r) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }); + + hyprListener_destroySurface.initCallback( + &surf_->events.destroy, + [this](void* owner, void* data) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }, + this, "CLayerShellResource"); + + hyprListener_commitSurface.initCallback( + &surf_->events.commit, + [this](void* owner, void* data) { + current = pending; + pending.committed = 0; + + bool attachedBuffer = surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0; + + if (attachedBuffer && !configured) { + wlr_surface_reject_pending(surface, resource->resource(), -1, "layerSurface was not configured, but a buffer was attached"); + return; + } + + constexpr uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + constexpr uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + + if (current.desiredSize.x <= 0 && (current.anchor & horiz) != horiz) { + wlr_surface_reject_pending(surface, resource->resource(), -1, "x == 0 but anchor doesn't have left and right"); + return; + } + + if (current.desiredSize.y <= 0 && (current.anchor & vert) != vert) { + wlr_surface_reject_pending(surface, resource->resource(), -1, "y == 0 but anchor doesn't have top and bottom"); + return; + } + + if (attachedBuffer && !mapped) { + mapped = true; + wlr_surface_map(surface); + events.map.emit(); + return; + } + + if (!attachedBuffer && mapped) { + mapped = false; + wlr_surface_unmap(surface); + events.unmap.emit(); + return; + } + + events.commit.emit(); + }, + this, "CLayerShellResource"); + + resource->setSetSize([this](CZwlrLayerSurfaceV1* r, uint32_t x, uint32_t y) { + pending.committed |= STATE_SIZE; + pending.desiredSize = {x, y}; + }); + + resource->setSetAnchor([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) { + if (anchor > (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR, "Invalid anchor"); + return; + } + + pending.committed |= STATE_ANCHOR; + pending.anchor = anchor; + }); + + resource->setSetExclusiveZone([this](CZwlrLayerSurfaceV1* r, int32_t zone) { + pending.committed |= STATE_EXCLUSIVE; + pending.exclusive = zone; + }); + + resource->setSetMargin([this](CZwlrLayerSurfaceV1* r, int32_t top, int32_t right, int32_t bottom, int32_t left) { + pending.committed |= STATE_MARGIN; + pending.margin = {left, right, top, bottom}; + }); + + resource->setSetKeyboardInteractivity([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1KeyboardInteractivity kbi) { + if (kbi > ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY, "Invalid keyboard interactivity"); + return; + } + + pending.committed |= STATE_INTERACTIVITY; + pending.interactivity = kbi; + }); + + resource->setGetPopup([this](CZwlrLayerSurfaceV1* r, wl_resource* popup_) { + auto popup = wlr_xdg_popup_from_resource(popup_); + + if (popup->parent) { + r->error(-1, "Parent already exists!"); + return; + } + + popup->parent = surface; + events.newPopup.emit(popup); + }); + + resource->setAckConfigure([this](CZwlrLayerSurfaceV1* r, uint32_t serial) { + auto serialFound = std::find_if(serials.begin(), serials.end(), [serial](const auto& e) { return e.first == serial; }); + + if (serialFound == serials.end()) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE, "Serial invalid in ack_configure"); + return; + } + + configured = true; + size = serialFound->second; + + serials.erase(serialFound); + }); + + resource->setSetLayer([this](CZwlrLayerSurfaceV1* r, uint32_t layer) { + if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { + r->error(ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, "Invalid layer"); + return; + } + + pending.committed |= STATE_LAYER; + pending.layer = (zwlrLayerShellV1Layer)layer; + }); + + resource->setSetExclusiveEdge([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) { + pending.committed |= STATE_EDGE; + pending.exclusiveEdge = anchor; + }); +} + +CLayerShellResource::~CLayerShellResource() { + events.destroy.emit(); +} + +bool CLayerShellResource::good() { + return resource->resource(); +} + +void CLayerShellResource::sendClosed() { + if (closed) + return; + closed = true; + resource->sendClosed(); +} + +void CLayerShellResource::configure(const Vector2D& size_) { + size = size_; + + auto serial = wl_display_next_serial(g_pCompositor->m_sWLDisplay); + + serials.push_back({serial, size_}); + + resource->sendConfigure(serial, size_.x, size_.y); +} + +CLayerShellProtocol::CLayerShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CLayerShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CZwlrLayerShellV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CZwlrLayerShellV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setGetLayerSurface([this](CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { + this->onGetLayerSurface(pMgr, id, surface, output, layer, namespace_); + }); +} + +void CLayerShellProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CLayerShellProtocol::destroyResource(CLayerShellResource* surf) { + std::erase_if(m_vLayers, [&](const auto& other) { return other.get() == surf; }); +} + +void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { + const auto CLIENT = pMgr->client(); + const auto PMONITOR = output ? g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)) : nullptr; + const auto RESOURCE = m_vLayers.emplace_back( + makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), namespace_, PMONITOR, layer)); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vLayers.pop_back(); + return; + } + + g_pCompositor->m_vLayers.emplace_back(CLayerSurface::create(RESOURCE)); + + LOGM(LOG, "New wlr_layer_surface {:x}", (uintptr_t)RESOURCE.get()); +} diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp new file mode 100644 index 00000000..9ed6bc66 --- /dev/null +++ b/src/protocols/LayerShell.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "wlr-layer-shell-unstable-v1.hpp" +#include "../helpers/Vector2D.hpp" +#include "../helpers/signal/Signal.hpp" + +class CMonitor; + +class CLayerShellResource { + public: + CLayerShellResource(SP resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); + ~CLayerShellResource(); + + bool good(); + void configure(const Vector2D& size); + void sendClosed(); + + enum eCommittedState { + STATE_SIZE = (1 << 0), + STATE_ANCHOR = (1 << 1), + STATE_EXCLUSIVE = (1 << 2), + STATE_MARGIN = (1 << 3), + STATE_INTERACTIVITY = (1 << 4), + STATE_LAYER = (1 << 5), + STATE_EDGE = (1 << 6), + }; + + struct { + CSignal destroy; + CSignal commit; + CSignal map; + CSignal unmap; + CSignal newPopup; // wlr_xdg_popup* + } events; + + struct SState { + uint32_t anchor = 0; + int32_t exclusive = 0; + Vector2D desiredSize; + zwlrLayerSurfaceV1KeyboardInteractivity interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; + zwlrLayerShellV1Layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; + zwlrLayerSurfaceV1Anchor exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + uint32_t committed = 0; + + struct { + double left = 0, right = 0, top = 0, bottom = 0; + } margin; + + void reset(); + } current, pending; + + Vector2D size; + std::string layerNamespace; + std::string monitor = ""; + wlr_surface* surface = nullptr; + bool mapped = false; + bool configured = false; + + private: + SP resource; + + DYNLISTENER(destroySurface); + DYNLISTENER(commitSurface); + + bool closed = false; + + std::vector> serials; +}; + +class CLayerShellProtocol : public IWaylandProtocol { + public: + CLayerShellProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CLayerShellResource* surf); + void onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_); + + // + std::vector> m_vManagers; + std::vector> m_vLayers; + + friend class CLayerShellResource; +}; + +namespace PROTO { + inline UP layerShell; +}; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 5cbac942..14a9dcba 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -6,6 +6,7 @@ #include #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" +#include "../protocols/LayerShell.hpp" inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a671bd40..76f761d2 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -9,6 +9,7 @@ #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/SessionLock.hpp" +#include "../protocols/LayerShell.hpp" extern "C" { #include @@ -709,8 +710,17 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time renderdata.dontRound = true; renderdata.popup = true; renderdata.blur = pLayer->forceBlurPopups; - if (popups) - wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata); + if (popups) { + pLayer->popupHead->breadthfirst( + [](CPopup* popup, void* data) { + if (!popup->m_sWLSurface.wlr()) + return; + + Vector2D pos = popup->coordsRelativeToParent(); + renderSurface(popup->m_sWLSurface.wlr(), pos.x, pos.y, data); + }, + &renderdata); + } g_pHyprOpenGL->m_pCurrentLayer = nullptr; g_pHyprOpenGL->m_RenderData.clipBox = {}; @@ -786,16 +796,16 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC g_pHyprOpenGL->blend(true); for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } g_pHyprOpenGL->m_RenderData.renderModif = {}; @@ -826,10 +836,10 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC g_pHyprOpenGL->blend(true); for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } g_pHyprOpenGL->m_RenderData.damage = preOccludedDamage; @@ -896,7 +906,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC // Render surfaces above windows for monitor for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } // Render IME popups @@ -905,12 +915,12 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { for (auto& ls : lsl) { - renderLayer(ls, pMonitor, time, true); + renderLayer(ls.lock(), pMonitor, time, true); } } @@ -1514,7 +1524,7 @@ static void applyExclusive(wlr_box& usableArea, uint32_t anchor, int32_t exclusi } } -void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { +void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { CBox full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto& ls : layerSurfaces) { @@ -1523,18 +1533,18 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorlayerSurface; const auto PSTATE = &PLAYER->current; - if (exclusiveZone != (PSTATE->exclusive_zone > 0)) + if (exclusiveZone != (PSTATE->exclusive > 0)) continue; CBox bounds; - if (PSTATE->exclusive_zone == -1) + if (PSTATE->exclusive == -1) bounds = full_area; else bounds = *usableArea; const Vector2D OLDSIZE = {ls->geometry.width, ls->geometry.height}; - CBox box = {0, 0, PSTATE->desired_width, PSTATE->desired_height}; + CBox box = {{}, PSTATE->desiredSize}; // Horizontal axis const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; if (box.width == 0) { @@ -1589,12 +1599,12 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgeometry = box; - applyExclusive(*usableArea->pWlr(), PSTATE->anchor, PSTATE->exclusive_zone, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); + applyExclusive(*usableArea->pWlr(), PSTATE->anchor, PSTATE->exclusive, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); usableArea->applyFromWlr(); if (Vector2D{box.width, box.height} != OLDSIZE) - wlr_layer_surface_v1_configure(ls->layerSurface, box.width, box.height); + ls->layerSurface->configure(box.size()); ls->realPosition = box.pos(); ls->realSize = box.size(); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 748a055f..da38fed2 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -105,7 +105,7 @@ class CHyprRenderer { } m_sLastCursorData; private: - void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); + void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);