diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2024-06-08 10:07:59 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-08 10:07:59 +0200 |
| commit | 6967a31450441fc5605c05db6f65505dace4b263 (patch) | |
| tree | 255a3cff7f3e2eb8a50c952eab9b270a7937561d /src/protocols/core/Subcompositor.cpp | |
| parent | c31d9ef4172452f6f219f91d9b87a24d91f0cf3a (diff) | |
wayland/core: move to new impl (#6268)
* wayland/core/dmabuf: move to new impl
it's the final countdown
Diffstat (limited to 'src/protocols/core/Subcompositor.cpp')
| -rw-r--r-- | src/protocols/core/Subcompositor.cpp | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp new file mode 100644 index 00000000..213fdc42 --- /dev/null +++ b/src/protocols/core/Subcompositor.cpp @@ -0,0 +1,192 @@ +#include "Subcompositor.hpp" +#include "Compositor.hpp" +#include <algorithm> + +#define LOGM PROTO::subcompositor->protoLog + +CWLSubsurfaceResource::CWLSubsurfaceResource(SP<CWlSubsurface> resource_, SP<CWLSurfaceResource> surface_, SP<CWLSurfaceResource> parent_) : + surface(surface_), parent(parent_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSubsurface* r) { destroy(); }); + resource->setDestroy([this](CWlSubsurface* r) { destroy(); }); + + resource->setSetPosition([this](CWlSubsurface* r, int32_t x, int32_t y) { position = {x, y}; }); + + resource->setSetDesync([this](CWlSubsurface* r) { sync = false; }); + resource->setSetSync([this](CWlSubsurface* r) { sync = true; }); + + resource->setPlaceAbove([this](CWlSubsurface* r, wl_resource* surf) { + auto SURF = CWLSurfaceResource::fromResource(surf); + + if (!parent) + return; + + std::erase(parent->subsurfaces, self.lock()); + + auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); + + if (it == parent->subsurfaces.end()) { + LOGM(ERR, "Invalid surface reference in placeAbove"); + parent->subsurfaces.emplace_back(self.lock()); + } else + parent->subsurfaces.insert(it, self.lock()); + }); + + resource->setPlaceBelow([this](CWlSubsurface* r, wl_resource* surf) { + auto SURF = CWLSurfaceResource::fromResource(surf); + + if (!parent) + return; + + std::erase(parent->subsurfaces, self.lock()); + + auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); + + if (it == parent->subsurfaces.end()) { + LOGM(ERR, "Invalid surface reference in placeBelow"); + parent->subsurfaces.emplace_back(self.lock()); + } else + parent->subsurfaces.insert(it--, self.lock()); + }); + + listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { + if (surface->current.buffer && !surface->mapped) { + surface->map(); + return; + } + + if (!surface->current.buffer && surface->mapped) { + surface->unmap(); + return; + } + }); +} + +CWLSubsurfaceResource::~CWLSubsurfaceResource() { + events.destroy.emit(); + if (surface) + surface->resetRole(); +} + +void CWLSubsurfaceResource::destroy() { + if (surface && surface->mapped) + surface->unmap(); + events.destroy.emit(); + PROTO::subcompositor->destroyResource(this); +} + +Vector2D CWLSubsurfaceResource::posRelativeToParent() { + Vector2D pos = position; + SP<CWLSurfaceResource> surf = parent.lock(); + + // some apps might create cycles, which I believe _technically_ are not a protocol error + // in some cases, notably firefox likes to do that, so we keep track of what + // surfaces we've visited and if we hit a surface we've visited we bail out. + std::vector<SP<CWLSurfaceResource>> surfacesVisited; + + while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && + std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + surfacesVisited.emplace_back(surf); + auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + pos += subsurface->position; + surf = subsurface->parent.lock(); + } + return pos; +} + +bool CWLSubsurfaceResource::good() { + return resource->resource(); +} + +eSurfaceRole CWLSubsurfaceResource::role() { + return SURFACE_ROLE_SUBSURFACE; +} + +SP<CWLSurfaceResource> CWLSubsurfaceResource::t1Parent() { + SP<CWLSurfaceResource> surf = parent.lock(); + std::vector<SP<CWLSurfaceResource>> surfacesVisited; + + while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && + std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + surfacesVisited.emplace_back(surf); + auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + surf = subsurface->parent.lock(); + } + return surf; +} + +CWLSubcompositorResource::CWLSubcompositorResource(SP<CWlSubcompositor> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSubcompositor* r) { PROTO::subcompositor->destroyResource(this); }); + resource->setDestroy([this](CWlSubcompositor* r) { PROTO::subcompositor->destroyResource(this); }); + + resource->setGetSubsurface([](CWlSubcompositor* r, uint32_t id, wl_resource* surface, wl_resource* parent) { + auto SURF = CWLSurfaceResource::fromResource(surface); + auto PARENT = CWLSurfaceResource::fromResource(parent); + + if (!SURF || !PARENT || SURF == PARENT) { + r->error(WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Invalid surface/parent"); + return; + } + + SP<CWLSurfaceResource> t1Parent = nullptr; + + if (PARENT->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)PARENT->role.get(); + t1Parent = subsurface->t1Parent(); + } else + t1Parent = PARENT; + + if (t1Parent == SURF) { + r->error(WL_SUBCOMPOSITOR_ERROR_BAD_PARENT, "Bad parent, t1 parent == surf"); + return; + } + + const auto RESOURCE = + PROTO::subcompositor->m_vSurfaces.emplace_back(makeShared<CWLSubsurfaceResource>(makeShared<CWlSubsurface>(r->client(), r->version(), id), SURF, PARENT)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::subcompositor->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + SURF->role = RESOURCE; + PARENT->subsurfaces.emplace_back(RESOURCE); + + LOGM(LOG, "New wl_subsurface with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); + + PARENT->events.newSubsurface.emit(RESOURCE); + }); +} + +bool CWLSubcompositorResource::good() { + return resource->resource(); +} + +CWLSubcompositorProtocol::CWLSubcompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLSubcompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared<CWLSubcompositorResource>(makeShared<CWlSubcompositor>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CWLSubcompositorProtocol::destroyResource(CWLSubcompositorResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSubcompositorProtocol::destroyResource(CWLSubsurfaceResource* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} |
