summaryrefslogtreecommitdiff
path: root/src/protocols/core/Subcompositor.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-06-08 10:07:59 +0200
committerGitHub <noreply@github.com>2024-06-08 10:07:59 +0200
commit6967a31450441fc5605c05db6f65505dace4b263 (patch)
tree255a3cff7f3e2eb8a50c952eab9b270a7937561d /src/protocols/core/Subcompositor.cpp
parentc31d9ef4172452f6f219f91d9b87a24d91f0cf3a (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.cpp192
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; });
+}