wayland/core: move to new impl (#6268)

* wayland/core/dmabuf: move to new impl

it's the final countdown
This commit is contained in:
Vaxry 2024-06-08 10:07:59 +02:00 committed by GitHub
parent c31d9ef417
commit 6967a31450
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
147 changed files with 5388 additions and 2226 deletions

View file

@ -2,10 +2,11 @@
#include <algorithm>
#include "../desktop/WLSurface.hpp"
#include "../render/Renderer.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::alphaModifier->protoLog
CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface_) : resource(resource_), pSurface(surface_) {
CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, SP<CWLSurfaceResource> surface_) : resource(resource_), pSurface(surface_) {
if (!resource->resource())
return;
@ -18,8 +19,7 @@ CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surf
setSurfaceAlpha(1.F);
});
hyprListener_surfaceDestroy.initCallback(
&surface_->events.destroy, [this](void* owner, void* data) { onSurfaceDestroy(); }, this, "CAlphaModifier");
listeners.destroySurface = pSurface->events.destroy.registerListener([this](std::any d) { onSurfaceDestroy(); });
resource->setSetMultiplier([this](CWpAlphaModifierSurfaceV1* mod, uint32_t alpha) {
if (!pSurface) {
@ -35,19 +35,19 @@ CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surf
}
CAlphaModifier::~CAlphaModifier() {
hyprListener_surfaceDestroy.removeCallback();
;
}
bool CAlphaModifier::good() {
return resource->resource();
}
wlr_surface* CAlphaModifier::getSurface() {
return pSurface;
SP<CWLSurfaceResource> CAlphaModifier::getSurface() {
return pSurface.lock();
}
void CAlphaModifier::setSurfaceAlpha(float a) {
CWLSurface* surf = CWLSurface::surfaceFromWlr(pSurface);
auto surf = CWLSurface::fromResource(pSurface.lock());
if (!surf) {
LOGM(ERR, "CAlphaModifier::setSurfaceAlpha: No CWLSurface for given surface??");
@ -62,8 +62,7 @@ void CAlphaModifier::setSurfaceAlpha(float a) {
}
void CAlphaModifier::onSurfaceDestroy() {
hyprListener_surfaceDestroy.removeCallback();
pSurface = nullptr;
pSurface.reset();
}
CAlphaModifierProtocol::CAlphaModifierProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
@ -75,7 +74,7 @@ void CAlphaModifierProtocol::bindManager(wl_client* client, void* data, uint32_t
RESOURCE->setOnDestroy([this](CWpAlphaModifierV1* p) { this->onManagerResourceDestroy(p->resource()); });
RESOURCE->setDestroy([this](CWpAlphaModifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, wlr_surface_from_resource(surface)); });
RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, CWLSurfaceResource::fromResource(surface)); });
}
void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) {
@ -83,29 +82,11 @@ void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) {
}
void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) {
if (modifier->getSurface())
m_mAlphaModifiers.erase(modifier->getSurface());
else {
// find it first
wlr_surface* deadptr = nullptr;
for (auto& [k, v] : m_mAlphaModifiers) {
if (v.get() == modifier) {
deadptr = k;
break;
}
}
if (!deadptr) {
LOGM(ERR, "CAlphaModifierProtocol::destroyModifier: dead resource but no deadptr???");
return;
}
m_mAlphaModifiers.erase(deadptr);
}
std::erase_if(m_mAlphaModifiers, [](const auto& e) { return e.first.expired(); });
}
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface) {
if (m_mAlphaModifiers.contains(surface)) {
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) {
LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface);
pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present");
return;

View file

@ -5,23 +5,28 @@
#include <unordered_map>
#include "WaylandProtocol.hpp"
#include "alpha-modifier-v1.hpp"
#include "../helpers/signal/Listener.hpp"
class CWLSurfaceResource;
class CAlphaModifier {
public:
CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface);
CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, SP<CWLSurfaceResource> surface);
~CAlphaModifier();
bool good();
wlr_surface* getSurface();
void onSurfaceDestroy();
bool good();
SP<CWLSurfaceResource> getSurface();
void onSurfaceDestroy();
private:
SP<CWpAlphaModifierSurfaceV1> resource;
wlr_surface* pSurface = nullptr;
WP<CWLSurfaceResource> pSurface;
void setSurfaceAlpha(float a);
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroySurface;
} listeners;
};
class CAlphaModifierProtocol : public IWaylandProtocol {
@ -33,15 +38,15 @@ class CAlphaModifierProtocol : public IWaylandProtocol {
private:
void onManagerResourceDestroy(wl_resource* res);
void destroyModifier(CAlphaModifier* decoration);
void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface);
void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface);
//
std::vector<UP<CWpAlphaModifierV1>> m_vManagers;
std::unordered_map<wlr_surface*, UP<CAlphaModifier>> m_mAlphaModifiers; // xdg_toplevel -> deco
std::vector<UP<CWpAlphaModifierV1>> m_vManagers;
std::unordered_map<WP<CWLSurfaceResource>, UP<CAlphaModifier>> m_mAlphaModifiers; // xdg_toplevel -> deco
friend class CAlphaModifier;
};
namespace PROTO {
inline UP<CAlphaModifierProtocol> alphaModifier;
};
};

View file

@ -1,21 +1,21 @@
#include "FocusGrab.hpp"
#include "Compositor.hpp"
#include "../Compositor.hpp"
#include <hyprland-focus-grab-v1.hpp>
#include "../managers/input/InputManager.hpp"
#include "../managers/SeatManager.hpp"
#include "core/Compositor.hpp"
#include <cstdint>
#include <memory>
#include <wayland-server.h>
#define LOGM PROTO::focusGrab->protoLog
CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) {
hyprListener_surfaceDestroy.initCallback(
&surface->events.destroy, [=](void*, void*) { grab->eraseSurface(surface); }, this, "CFocusGrab");
CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP<CWLSurfaceResource> surface) {
listeners.destroy = surface->events.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); });
}
CFocusGrabSurfaceState::~CFocusGrabSurfaceState() {
hyprListener_surfaceDestroy.removeCallback();
;
}
CFocusGrab::CFocusGrab(SP<CHyprlandFocusGrabV1> resource_) : resource(resource_) {
@ -29,8 +29,8 @@ CFocusGrab::CFocusGrab(SP<CHyprlandFocusGrabV1> resource_) : resource(resource_)
resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); });
resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(wlr_surface_from_resource(surface)); });
resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(wlr_surface_from_resource(surface)); });
resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(CWLSurfaceResource::fromResource(surface)); });
resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(CWLSurfaceResource::fromResource(surface)); });
resource->setCommit([this](CHyprlandFocusGrabV1* pMgr) { commit(); });
}
@ -42,8 +42,8 @@ bool CFocusGrab::good() {
return resource->resource();
}
bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) {
auto iter = m_mSurfaces.find(surface);
bool CFocusGrab::isSurfaceComitted(SP<CWLSurfaceResource> surface) {
auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& o) { return o.first == surface; });
if (iter == m_mSurfaces.end())
return false;
@ -77,14 +77,14 @@ void CFocusGrab::finish(bool sendCleared) {
}
}
void CFocusGrab::addSurface(wlr_surface* surface) {
auto iter = m_mSurfaces.find(surface);
void CFocusGrab::addSurface(SP<CWLSurfaceResource> surface) {
auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& e) { return e.first == surface; });
if (iter == m_mSurfaces.end()) {
m_mSurfaces.emplace(surface, std::make_unique<CFocusGrabSurfaceState>(this, surface));
}
}
void CFocusGrab::removeSurface(wlr_surface* surface) {
void CFocusGrab::removeSurface(SP<CWLSurfaceResource> surface) {
auto iter = m_mSurfaces.find(surface);
if (iter != m_mSurfaces.end()) {
if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) {
@ -94,20 +94,20 @@ void CFocusGrab::removeSurface(wlr_surface* surface) {
}
}
void CFocusGrab::eraseSurface(wlr_surface* surface) {
void CFocusGrab::eraseSurface(SP<CWLSurfaceResource> surface) {
removeSurface(surface);
commit(true);
}
void CFocusGrab::refocusKeyboard() {
auto keyboardSurface = g_pSeatManager->state.keyboardFocus;
if (keyboardSurface != nullptr && isSurfaceComitted(keyboardSurface))
if (keyboardSurface && isSurfaceComitted(keyboardSurface.lock()))
return;
wlr_surface* surface = nullptr;
SP<CWLSurfaceResource> surface = nullptr;
for (auto& [surf, state] : m_mSurfaces) {
if (state->state == CFocusGrabSurfaceState::Comitted) {
surface = surf;
surface = surf.lock();
break;
}
}
@ -124,14 +124,14 @@ void CFocusGrab::commit(bool removeOnly) {
for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) {
switch (iter->second->state) {
case CFocusGrabSurfaceState::PendingRemoval:
grab->remove(iter->first);
grab->remove(iter->first.lock());
iter = m_mSurfaces.erase(iter);
surfacesChanged = true;
continue;
case CFocusGrabSurfaceState::PendingAddition:
if (!removeOnly) {
iter->second->state = CFocusGrabSurfaceState::Comitted;
grab->add(iter->first);
grab->add(iter->first.lock());
surfacesChanged = true;
anyComitted = true;
}

View file

@ -6,13 +6,15 @@
#include <cstdint>
#include <unordered_map>
#include <vector>
#include "../helpers/signal/Listener.hpp"
class CFocusGrab;
class CSeatGrab;
class CWLSurfaceResource;
class CFocusGrabSurfaceState {
public:
CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface);
CFocusGrabSurfaceState(CFocusGrab* grab, SP<CWLSurfaceResource> surface);
~CFocusGrabSurfaceState();
enum State {
@ -22,7 +24,9 @@ class CFocusGrabSurfaceState {
} state = PendingAddition;
private:
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroy;
} listeners;
};
class CFocusGrab {
@ -31,23 +35,23 @@ class CFocusGrab {
~CFocusGrab();
bool good();
bool isSurfaceComitted(wlr_surface* surface);
bool isSurfaceComitted(SP<CWLSurfaceResource> surface);
void start();
void finish(bool sendCleared);
private:
void addSurface(wlr_surface* surface);
void removeSurface(wlr_surface* surface);
void eraseSurface(wlr_surface* surface);
void refocusKeyboard();
void commit(bool removeOnly = false);
void addSurface(SP<CWLSurfaceResource> surface);
void removeSurface(SP<CWLSurfaceResource> surface);
void eraseSurface(SP<CWLSurfaceResource> surface);
void refocusKeyboard();
void commit(bool removeOnly = false);
SP<CHyprlandFocusGrabV1> resource;
std::unordered_map<wlr_surface*, UP<CFocusGrabSurfaceState>> m_mSurfaces;
SP<CSeatGrab> grab;
SP<CHyprlandFocusGrabV1> resource;
std::unordered_map<WP<CWLSurfaceResource>, UP<CFocusGrabSurfaceState>> m_mSurfaces;
SP<CSeatGrab> grab;
bool m_bGrabActive = false;
bool m_bGrabActive = false;
DYNLISTENER(pointerGrabStarted);
DYNLISTENER(keyboardGrabStarted);

View file

@ -1,13 +1,9 @@
#include "FractionalScale.hpp"
#include <algorithm>
#include "core/Compositor.hpp"
#define LOGM PROTO::fractional->protoLog
static void onWlrSurfaceDestroy(void* owner, void* data) {
const auto SURF = (wlr_surface*)owner;
PROTO::fractional->onSurfaceDestroy(SURF);
}
CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
@ -18,7 +14,7 @@ void CFractionalScaleProtocol::bindManager(wl_client* client, void* data, uint32
RESOURCE->setDestroy([this](CWpFractionalScaleManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setGetFractionalScale(
[this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, wlr_surface_from_resource(surface)); });
[this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, CWLSurfaceResource::fromResource(surface)); });
}
void CFractionalScaleProtocol::removeAddon(CFractionalScaleAddon* addon) {
@ -29,11 +25,13 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) {
std::erase_if(m_vManagers, [res](const auto& other) { return other->resource() == res; });
}
void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface) {
if (m_mAddons.contains(surface)) {
LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface);
pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists");
return;
void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
for (auto& [k, v] : m_mAddons) {
if (k == surface) {
LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface);
pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists");
return;
}
}
const auto PADDON =
@ -48,35 +46,22 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1*
PADDON->resource->setOnDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); });
PADDON->resource->setDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); });
if (!m_mSurfaceScales.contains(surface))
m_mSurfaceScales[surface] = 1.F;
if (std::find_if(m_mSurfaceScales.begin(), m_mSurfaceScales.end(), [surface](const auto& e) { return e.first == surface; }) == m_mSurfaceScales.end())
m_mSurfaceScales.emplace(surface, 1.F);
PADDON->setScale(m_mSurfaceScales[surface]);
registerSurface(surface);
PADDON->setScale(m_mSurfaceScales.at(surface));
// clean old
std::erase_if(m_mSurfaceScales, [](const auto& e) { return e.first.expired(); });
}
void CFractionalScaleProtocol::sendScale(wlr_surface* surf, const float& scale) {
void CFractionalScaleProtocol::sendScale(SP<CWLSurfaceResource> surf, const float& scale) {
m_mSurfaceScales[surf] = scale;
if (m_mAddons.contains(surf))
m_mAddons[surf]->setScale(scale);
registerSurface(surf);
}
void CFractionalScaleProtocol::registerSurface(wlr_surface* surf) {
if (m_mSurfaceDestroyListeners.contains(surf))
return;
m_mSurfaceDestroyListeners[surf].hyprListener_surfaceDestroy.initCallback(&surf->events.destroy, ::onWlrSurfaceDestroy, surf, "FractionalScale");
}
void CFractionalScaleProtocol::onSurfaceDestroy(wlr_surface* surf) {
m_mSurfaceDestroyListeners.erase(surf);
m_mSurfaceScales.erase(surf);
if (m_mAddons.contains(surf))
m_mAddons[surf]->onSurfaceDestroy();
}
CFractionalScaleAddon::CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) {
CFractionalScaleAddon::CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, SP<CWLSurfaceResource> surf_) : resource(resource_), surface(surf_) {
resource->setDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); });
resource->setOnDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); });
}
@ -93,6 +78,6 @@ bool CFractionalScaleAddon::good() {
return resource->resource();
}
wlr_surface* CFractionalScaleAddon::surf() {
return surface;
SP<CWLSurfaceResource> CFractionalScaleAddon::surf() {
return surface.lock();
}

View file

@ -6,19 +6,20 @@
#include "fractional-scale-v1.hpp"
class CFractionalScaleProtocol;
class CWLSurfaceResource;
class CFractionalScaleAddon {
public:
CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, wlr_surface* surf_);
CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, SP<CWLSurfaceResource> surf_);
void setScale(const float& scale);
void onSurfaceDestroy();
void setScale(const float& scale);
void onSurfaceDestroy();
bool good();
bool good();
wlr_surface* surf();
SP<CWLSurfaceResource> surf();
bool operator==(const wl_resource* other) const {
bool operator==(const wl_resource* other) const {
return other == resource->resource();
}
@ -28,42 +29,36 @@ class CFractionalScaleAddon {
private:
SP<CWpFractionalScaleV1> resource;
float scale = 1.F;
wlr_surface* surface = nullptr;
float scale = 1.F;
WP<CWLSurfaceResource> surface;
bool surfaceGone = false;
friend class CFractionalScaleProtocol;
};
struct SSurfaceListener {
DYNLISTENER(surfaceDestroy);
};
class CFractionalScaleProtocol : public IWaylandProtocol {
public:
CFractionalScaleProtocol(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);
void onSurfaceDestroy(wlr_surface* surf);
void sendScale(wlr_surface* surf, const float& scale);
void onSurfaceDestroy(SP<CWLSurfaceResource> surf);
void sendScale(SP<CWLSurfaceResource> surf, const float& scale);
private:
void removeAddon(CFractionalScaleAddon*);
void registerSurface(wlr_surface*);
void onManagerResourceDestroy(wl_resource* res);
void onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface);
void onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface);
//
std::unordered_map<wlr_surface*, SSurfaceListener> m_mSurfaceDestroyListeners;
std::unordered_map<wlr_surface*, float> m_mSurfaceScales;
std::unordered_map<wlr_surface*, UP<CFractionalScaleAddon>> m_mAddons;
std::vector<UP<CWpFractionalScaleManagerV1>> m_vManagers;
std::unordered_map<WP<CWLSurfaceResource>, float> m_mSurfaceScales;
std::unordered_map<WP<CWLSurfaceResource>, UP<CFractionalScaleAddon>> m_mAddons;
std::vector<UP<CWpFractionalScaleManagerV1>> m_vManagers;
friend class CFractionalScaleAddon;
};
namespace PROTO {
inline UP<CFractionalScaleProtocol> fractional;
};
};

View file

@ -3,6 +3,7 @@
#include <unistd.h>
#include "../helpers/Monitor.hpp"
#include "../Compositor.hpp"
#include "../protocols/core/Output.hpp"
#define LOGM PROTO::gamma->protoLog
@ -10,15 +11,15 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out
if (!resource_->resource())
return;
wlr_output* wlrOutput = wlr_output_from_resource(output);
auto OUTPUTRES = CWLOutputResource::fromResource(output);
if (!wlrOutput) {
LOGM(ERR, "No wlr_output in CGammaControl");
if (!OUTPUTRES) {
LOGM(ERR, "No output in CGammaControl");
resource->sendFailed();
return;
}
pMonitor = g_pCompositor->getRealMonitorFromOutput(wlrOutput);
pMonitor = OUTPUTRES->monitor.get();
if (!pMonitor) {
LOGM(ERR, "No CMonitor");
@ -33,7 +34,7 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out
}
}
gammaSize = wlr_output_get_gamma_size(wlrOutput);
gammaSize = wlr_output_get_gamma_size(pMonitor->output);
if (gammaSize <= 0) {
LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName);

View file

@ -1,26 +1,23 @@
#include "IdleInhibit.hpp"
#include "core/Compositor.hpp"
CIdleInhibitor::CIdleInhibitor(SP<CIdleInhibitorResource> resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) {
CIdleInhibitor::CIdleInhibitor(SP<CIdleInhibitorResource> resource_, SP<CWLSurfaceResource> surf_) : resource(resource_), surface(surf_) {
;
}
CIdleInhibitorResource::CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, wlr_surface* surface_) : resource(resource_), surface(surface_) {
hyprListener_surfaceDestroy.initCallback(
&surface->events.destroy,
[this](void* owner, void* data) {
surface = nullptr;
hyprListener_surfaceDestroy.removeCallback();
destroySent = true;
events.destroy.emit();
},
this, "CIdleInhibitorResource");
CIdleInhibitorResource::CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, SP<CWLSurfaceResource> surface_) : resource(resource_), surface(surface_) {
listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) {
surface.reset();
listeners.destroySurface.reset();
destroySent = true;
events.destroy.emit();
});
resource->setOnDestroy([this](CZwpIdleInhibitorV1* p) { PROTO::idleInhibit->removeInhibitor(this); });
resource->setDestroy([this](CZwpIdleInhibitorV1* p) { PROTO::idleInhibit->removeInhibitor(this); });
}
CIdleInhibitorResource::~CIdleInhibitorResource() {
hyprListener_surfaceDestroy.removeCallback();
if (!destroySent)
events.destroy.emit();
}
@ -39,14 +36,14 @@ void CIdleInhibitProtocol::bindManager(wl_client* client, void* data, uint32_t v
RESOURCE->setDestroy([this](CZwpIdleInhibitManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setCreateInhibitor(
[this](CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onCreateInhibitor(pMgr, id, wlr_surface_from_resource(surface)); });
[this](CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onCreateInhibitor(pMgr, id, CWLSurfaceResource::fromResource(surface)); });
}
void CIdleInhibitProtocol::removeInhibitor(CIdleInhibitorResource* resource) {
std::erase_if(m_vInhibitors, [resource](const auto& el) { return el.get() == resource; });
}
void CIdleInhibitProtocol::onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wlr_surface* surface) {
void CIdleInhibitProtocol::onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
const auto CLIENT = pMgr->client();
const auto RESOURCE = m_vInhibitors.emplace_back(makeShared<CIdleInhibitorResource>(makeShared<CZwpIdleInhibitorV1>(CLIENT, pMgr->version(), id), surface));

View file

@ -7,22 +7,23 @@
#include "../helpers/signal/Signal.hpp"
class CIdleInhibitorResource;
class CWLSurfaceResource;
class CIdleInhibitor {
public:
CIdleInhibitor(SP<CIdleInhibitorResource> resource_, wlr_surface* surf_);
CIdleInhibitor(SP<CIdleInhibitorResource> resource_, SP<CWLSurfaceResource> surf_);
struct {
CHyprSignalListener destroy;
} listeners;
WP<CIdleInhibitorResource> resource;
wlr_surface* surface = nullptr;
WP<CWLSurfaceResource> surface;
};
class CIdleInhibitorResource {
public:
CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, wlr_surface* surface_);
CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, SP<CWLSurfaceResource> surface_);
~CIdleInhibitorResource();
SP<CIdleInhibitor> inhibitor;
@ -33,10 +34,12 @@ class CIdleInhibitorResource {
private:
SP<CZwpIdleInhibitorV1> resource;
wlr_surface* surface = nullptr;
WP<CWLSurfaceResource> surface;
bool destroySent = false;
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroySurface;
} listeners;
};
class CIdleInhibitProtocol : public IWaylandProtocol {
@ -51,7 +54,7 @@ class CIdleInhibitProtocol : public IWaylandProtocol {
private:
void onManagerResourceDestroy(wl_resource* res);
void onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wlr_surface* surface);
void onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface);
void removeInhibitor(CIdleInhibitorResource*);
@ -64,4 +67,4 @@ class CIdleInhibitProtocol : public IWaylandProtocol {
namespace PROTO {
inline UP<CIdleInhibitProtocol> idleInhibit;
}
}

View file

@ -3,6 +3,7 @@
#include "../managers/SeatManager.hpp"
#include "../devices/IKeyboard.hpp"
#include <sys/mman.h>
#include "core/Compositor.hpp"
#define LOGM PROTO::ime->protoLog
@ -83,51 +84,45 @@ wl_client* CInputMethodKeyboardGrabV2::client() {
return resource->client();
}
CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, wlr_surface* wlrSurface) : resource(resource_), owner(owner_) {
CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, SP<CWLSurfaceResource> surface) : resource(resource_), owner(owner_) {
if (!resource->resource())
return;
resource->setDestroy([this](CZwpInputPopupSurfaceV2* r) { PROTO::ime->destroyResource(this); });
resource->setOnDestroy([this](CZwpInputPopupSurfaceV2* r) { PROTO::ime->destroyResource(this); });
pSurface = wlrSurface;
pSurface = surface;
hyprListener_destroySurface.initCallback(
&wlrSurface->events.destroy,
[this](void* owner, void* data) {
if (mapped)
events.unmap.emit();
listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) {
if (mapped)
events.unmap.emit();
hyprListener_commitSurface.removeCallback();
hyprListener_destroySurface.removeCallback();
listeners.destroySurface.reset();
listeners.commitSurface.reset();
if (g_pCompositor->m_pLastFocus == pSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pCompositor->m_pLastFocus == pSurface)
g_pCompositor->m_pLastFocus.reset();
pSurface = nullptr;
},
this, "IMEPopup");
pSurface.reset();
});
hyprListener_commitSurface.initCallback(
&wlrSurface->events.commit,
[this](void* owner, void* data) {
if (pSurface->pending.buffer_width > 0 && pSurface->pending.buffer_height > 0 && !mapped) {
mapped = true;
wlr_surface_map(pSurface);
events.map.emit();
return;
}
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
if (pSurface->current.buffer && !mapped) {
mapped = true;
pSurface->map();
events.map.emit();
return;
}
if (pSurface->pending.buffer_width <= 0 && pSurface->pending.buffer_height <= 0 && mapped) {
mapped = false;
wlr_surface_unmap(pSurface);
events.unmap.emit();
return;
}
if (!pSurface->current.buffer && mapped) {
mapped = false;
pSurface->unmap();
events.unmap.emit();
return;
}
events.commit.emit();
},
this, "IMEPopup");
events.commit.emit();
});
}
CInputMethodPopupV2::~CInputMethodPopupV2() {
@ -145,8 +140,8 @@ void CInputMethodPopupV2::sendInputRectangle(const CBox& box) {
resource->sendTextInputRectangle(box.x, box.y, box.w, box.h);
}
wlr_surface* CInputMethodPopupV2::surface() {
return pSurface;
SP<CWLSurfaceResource> CInputMethodPopupV2::surface() {
return pSurface.lock();
}
void CInputMethodV2::SState::reset() {
@ -194,7 +189,7 @@ CInputMethodV2::CInputMethodV2(SP<CZwpInputMethodV2> resource_) : resource(resou
resource->setGetInputPopupSurface([this](CZwpInputMethodV2* r, uint32_t id, wl_resource* surface) {
const auto RESOURCE = PROTO::ime->m_vPopups.emplace_back(
makeShared<CInputMethodPopupV2>(makeShared<CZwpInputPopupSurfaceV2>(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surface)));
makeShared<CInputMethodPopupV2>(makeShared<CZwpInputPopupSurfaceV2>(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surface)));
if (!RESOURCE->good()) {
r->noMemory();

View file

@ -101,12 +101,12 @@ class CInputMethodKeyboardGrabV2 {
class CInputMethodPopupV2 {
public:
CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, wlr_surface* surface);
CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, SP<CWLSurfaceResource> surface);
~CInputMethodPopupV2();
bool good();
void sendInputRectangle(const CBox& box);
wlr_surface* surface();
bool good();
void sendInputRectangle(const CBox& box);
SP<CWLSurfaceResource> surface();
struct {
CSignal map;
@ -120,10 +120,12 @@ class CInputMethodPopupV2 {
private:
SP<CZwpInputPopupSurfaceV2> resource;
WP<CInputMethodV2> owner;
wlr_surface* pSurface = nullptr;
WP<CWLSurfaceResource> pSurface;
DYNLISTENER(commitSurface);
DYNLISTENER(destroySurface);
struct {
CHyprSignalListener destroySurface;
CHyprSignalListener commitSurface;
} listeners;
};
class CInputMethodV2Protocol : public IWaylandProtocol {

View file

@ -1,6 +1,8 @@
#include "LayerShell.hpp"
#include "../Compositor.hpp"
#include "XDGShell.hpp"
#include "core/Compositor.hpp"
#include "core/Output.hpp"
#define LOGM PROTO::layerShell->protoLog
@ -14,7 +16,7 @@ void CLayerShellResource::SState::reset() {
margin = {0, 0, 0, 0};
}
CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) :
CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<CWLSurfaceResource> surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) :
layerNamespace(namespace_), surface(surf_), resource(resource_) {
if (!good())
return;
@ -31,57 +33,52 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, wlr_
PROTO::layerShell->destroyResource(this);
});
hyprListener_destroySurface.initCallback(
&surf_->events.destroy,
[this](void* owner, void* data) {
events.destroy.emit();
PROTO::layerShell->destroyResource(this);
},
this, "CLayerShellResource");
listeners.destroySurface = surf_->events.destroy.registerListener([this](std::any d) {
events.destroy.emit();
PROTO::layerShell->destroyResource(this);
});
hyprListener_commitSurface.initCallback(
&surf_->events.commit,
[this](void* owner, void* data) {
current = pending;
pending.committed = 0;
listeners.commitSurface = surf_->events.commit.registerListener([this](std::any d) {
current = pending;
pending.committed = 0;
bool attachedBuffer = surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0;
bool attachedBuffer = surface->current.buffer;
if (attachedBuffer && !configured) {
wlr_surface_reject_pending(surface, resource->resource(), -1, "layerSurface was not configured, but a buffer was attached");
return;
}
if (attachedBuffer && !configured) {
surface->error(-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;
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.x <= 0 && (current.anchor & horiz) != horiz) {
surface->error(-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 (current.desiredSize.y <= 0 && (current.anchor & vert) != vert) {
surface->error(-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 = true;
surface->map();
events.map.emit();
return;
}
if (!attachedBuffer && mapped) {
mapped = false;
wlr_surface_unmap(surface);
events.unmap.emit();
return;
}
if (!attachedBuffer && mapped) {
mapped = false;
surface->unmap();
events.unmap.emit();
configured = false;
return;
}
events.commit.emit();
},
this, "CLayerShellResource");
events.commit.emit();
});
resource->setSetSize([this](CZwlrLayerSurfaceV1* r, uint32_t x, uint32_t y) {
pending.committed |= STATE_SIZE;
@ -209,9 +206,9 @@ void CLayerShellProtocol::destroyResource(CLayerShellResource* 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 PMONITOR = output ? CWLOutputResource::fromResource(output)->monitor.get() : nullptr;
const auto RESOURCE = m_vLayers.emplace_back(
makeShared<CLayerShellResource>(makeShared<CZwlrLayerSurfaceV1>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), namespace_, PMONITOR, layer));
makeShared<CLayerShellResource>(makeShared<CZwlrLayerSurfaceV1>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), namespace_, PMONITOR, layer));
if (!RESOURCE->good()) {
pMgr->noMemory();

View file

@ -10,10 +10,11 @@
#include "../helpers/signal/Signal.hpp"
class CMonitor;
class CWLSurfaceResource;
class CLayerShellResource {
public:
CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer);
CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<CWLSurfaceResource> surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer);
~CLayerShellResource();
bool good();
@ -54,18 +55,20 @@ class CLayerShellResource {
void reset();
} current, pending;
Vector2D size;
std::string layerNamespace;
std::string monitor = "";
wlr_surface* surface = nullptr;
bool mapped = false;
bool configured = false;
Vector2D size;
std::string layerNamespace;
std::string monitor = "";
WP<CWLSurfaceResource> surface;
bool mapped = false;
bool configured = false;
private:
SP<CZwlrLayerSurfaceV1> resource;
DYNLISTENER(destroySurface);
DYNLISTENER(commitSurface);
struct {
CHyprSignalListener commitSurface;
CHyprSignalListener destroySurface;
} listeners;
bool closed = false;

View file

@ -0,0 +1,454 @@
#include "LinuxDMABUF.hpp"
#include <algorithm>
#include <set>
#include <tuple>
#include "../helpers/MiscFunctions.hpp"
#include <sys/mman.h>
#include <xf86drm.h>
#include <fcntl.h>
#include "core/Compositor.hpp"
#include "types/DMABuffer.hpp"
#include "types/WLBuffer.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../render/OpenGL.hpp"
#include "../Compositor.hpp"
#define LOGM PROTO::linuxDma->protoLog
static std::optional<dev_t> devIDFromFD(int fd) {
struct stat stat;
if (fstat(fd, &stat) != 0)
return {};
return stat.st_rdev;
}
CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches_) {
std::set<std::pair<uint32_t, uint64_t>> formats;
for (auto& t : tranches_) {
for (auto& fmt : t.formats) {
for (auto& mod : fmt.mods) {
formats.insert(std::make_pair<>(fmt.format, mod));
}
}
}
tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry);
int fds[2] = {0};
allocateSHMFilePair(tableLen, &fds[0], &fds[1]);
auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0);
if (!arr) {
LOGM(ERR, "mmap failed");
close(fds[0]);
close(fds[1]);
return;
}
close(fds[0]);
std::vector<std::pair<uint32_t, uint64_t>> formatsVec;
for (auto& f : formats) {
formatsVec.push_back(f);
}
size_t i = 0;
for (auto& [fmt, mod] : formatsVec) {
arr[i++] = SDMABUFFeedbackTableEntry{
.fmt = fmt,
.modifier = mod,
};
}
munmap(arr, tableLen);
mainDevice = device;
tableFD = fds[1];
tranches = formatsVec;
// TODO: maybe calculate indices? currently we send all as available which could be wrong? I ain't no kernel dev tho.
}
CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() {
close(tableFD);
}
CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) {
buffer = makeShared<CDMABuffer>(id, client, attrs);
buffer->resource->buffer = buffer;
listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) {
listeners.bufferResourceDestroy.reset();
PROTO::linuxDma->destroyResource(this);
});
if (!buffer->success)
LOGM(ERR, "Possibly compositor bug: buffer failed to create");
}
CLinuxDMABuffer::~CLinuxDMABuffer() {
buffer.reset();
listeners.bufferResourceDestroy.reset();
}
bool CLinuxDMABuffer::good() {
return buffer && buffer->good();
}
CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParamsV1> resource_) : resource(resource_) {
if (!good())
return;
resource->setOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
attrs = makeShared<SDMABUFAttrs>();
attrs->success = true;
resource->setAdd([this](CZwpLinuxBufferParamsV1* r, int32_t fd, uint32_t plane, uint32_t offset, uint32_t stride, uint32_t modHi, uint32_t modLo) {
if (used) {
r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used");
return;
}
if (plane > 3) {
r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, "plane > 3");
return;
}
if (attrs->fds.at(plane) != -1) {
r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, "plane used");
return;
}
attrs->fds[plane] = fd;
attrs->strides[plane] = stride;
attrs->offsets[plane] = offset;
attrs->modifier = ((uint64_t)modHi << 32) | modLo;
});
resource->setCreate([this](CZwpLinuxBufferParamsV1* r, int32_t w, int32_t h, uint32_t fmt, zwpLinuxBufferParamsV1Flags flags) {
if (used) {
r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used");
return;
}
if (flags > 0) {
r->sendFailed();
LOGM(ERR, "DMABUF flags are not supported");
return;
}
attrs->size = {w, h};
attrs->format = fmt;
attrs->planes = 4 - std::count(attrs->fds.begin(), attrs->fds.end(), -1);
create(0);
});
resource->setCreateImmed([this](CZwpLinuxBufferParamsV1* r, uint32_t id, int32_t w, int32_t h, uint32_t fmt, zwpLinuxBufferParamsV1Flags flags) {
if (used) {
r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used");
return;
}
if (flags > 0) {
r->sendFailed();
LOGM(ERR, "DMABUF flags are not supported");
return;
}
attrs->size = {w, h};
attrs->format = fmt;
attrs->planes = 4 - std::count(attrs->fds.begin(), attrs->fds.end(), -1);
create(id);
});
}
CLinuxDMABBUFParamsResource::~CLinuxDMABBUFParamsResource() {
;
}
bool CLinuxDMABBUFParamsResource::good() {
return resource->resource();
}
void CLinuxDMABBUFParamsResource::create(uint32_t id) {
used = true;
if (!verify()) {
LOGM(ERR, "Failed creating a dmabuf: verify() said no");
return; // if verify failed, we errored the resource.
}
if (!commence()) {
LOGM(ERR, "Failed creating a dmabuf: commence() said no");
resource->sendFailed();
return;
}
LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, attrs->format, attrs->planes);
for (int i = 0; i < attrs->planes; ++i) {
LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs->modifier, attrs->fds[i], attrs->strides[i], attrs->offsets[i]);
}
auto buf = PROTO::linuxDma->m_vBuffers.emplace_back(makeShared<CLinuxDMABuffer>(id, resource->client(), *attrs));
if (!buf->good() || !buf->buffer->success) {
resource->sendFailed();
return;
}
if (!id)
resource->sendCreated(PROTO::linuxDma->m_vBuffers.back()->buffer->resource->getResource());
createdBuffer = buf;
}
bool CLinuxDMABBUFParamsResource::commence() {
if (PROTO::linuxDma->mainDeviceFD < 0)
return true;
for (int i = 0; i < attrs->planes; i++) {
uint32_t handle = 0;
if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD, attrs->fds.at(i), &handle)) {
LOGM(ERR, "Failed to import dmabuf fd");
return false;
}
if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD, handle)) {
LOGM(ERR, "Failed to close dmabuf handle");
return false;
}
}
return true;
}
bool CLinuxDMABBUFParamsResource::verify() {
if (attrs->planes <= 0) {
resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No planes added");
return false;
}
if (attrs->fds.at(0) < 0) {
resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No plane 0");
return false;
}
bool empty = false;
for (auto& plane : attrs->fds) {
if (empty && plane != -1) {
resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "Gap in planes");
return false;
}
if (plane == -1) {
empty = true;
continue;
}
}
if (attrs->size.x < 1 || attrs->size.y < 1) {
resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS, "x/y < 1");
return false;
}
for (size_t i = 0; i < (size_t)attrs->planes; ++i) {
if ((uint64_t)attrs->offsets.at(i) + (uint64_t)attrs->strides.at(i) * attrs->size.y > UINT32_MAX) {
resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
std::format("size overflow on plane {}: offset {} + stride {} * height {} = {}, overflows UINT32_MAX", i, (uint64_t)attrs->offsets.at(i),
(uint64_t)attrs->strides.at(i), attrs->size.y, (uint64_t)attrs->offsets.at(i) + (uint64_t)attrs->strides.at(i)));
return false;
}
}
return true;
}
CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SP<CZwpLinuxDmabufFeedbackV1> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) {
if (!good())
return;
resource->setOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); });
resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); });
if (surface)
LOGM(ERR, "FIXME: surface feedback stub");
auto* feedback = PROTO::linuxDma->defaultFeedback.get();
resource->sendFormatTable(feedback->tableFD, feedback->tableLen);
// send default feedback
struct wl_array deviceArr = {
.size = sizeof(feedback->mainDevice),
.data = (void*)&feedback->mainDevice,
};
resource->sendMainDevice(&deviceArr);
resource->sendTrancheTargetDevice(&deviceArr);
resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)0);
wl_array indices;
wl_array_init(&indices);
for (size_t i = 0; i < feedback->tranches.size(); ++i) {
*((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i;
}
resource->sendTrancheFormats(&indices);
wl_array_release(&indices);
resource->sendTrancheDone();
resource->sendDone();
}
CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() {
;
}
bool CLinuxDMABUFFeedbackResource::good() {
return resource->resource();
}
CLinuxDMABUFResource::CLinuxDMABUFResource(SP<CZwpLinuxDmabufV1> resource_) : resource(resource_) {
if (!good())
return;
resource->setOnDestroy([this](CZwpLinuxDmabufV1* r) { PROTO::linuxDma->destroyResource(this); });
resource->setDestroy([this](CZwpLinuxDmabufV1* r) { PROTO::linuxDma->destroyResource(this); });
resource->setGetDefaultFeedback([](CZwpLinuxDmabufV1* r, uint32_t id) {
const auto RESOURCE =
PROTO::linuxDma->m_vFeedbacks.emplace_back(makeShared<CLinuxDMABUFFeedbackResource>(makeShared<CZwpLinuxDmabufFeedbackV1>(r->client(), r->version(), id), nullptr));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::linuxDma->m_vFeedbacks.pop_back();
return;
}
});
resource->setGetSurfaceFeedback([](CZwpLinuxDmabufV1* r, uint32_t id, wl_resource* surf) {
const auto RESOURCE = PROTO::linuxDma->m_vFeedbacks.emplace_back(
makeShared<CLinuxDMABUFFeedbackResource>(makeShared<CZwpLinuxDmabufFeedbackV1>(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf)));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::linuxDma->m_vFeedbacks.pop_back();
return;
}
});
resource->setCreateParams([](CZwpLinuxDmabufV1* r, uint32_t id) {
const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared<CLinuxDMABBUFParamsResource>(makeShared<CZwpLinuxBufferParamsV1>(r->client(), r->version(), id)));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::linuxDma->m_vParams.pop_back();
return;
}
});
if (resource->version() < 4)
sendMods();
}
bool CLinuxDMABUFResource::good() {
return resource->resource();
}
void CLinuxDMABUFResource::sendMods() {
for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->tranches) {
if (resource->version() < 3) {
if (mod == DRM_FORMAT_MOD_INVALID)
resource->sendFormat(fmt);
continue;
}
// TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166
resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF);
}
}
CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) {
int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
auto dev = devIDFromFD(rendererFD);
if (!dev.has_value()) {
LOGM(ERR, "failed to get drm dev");
PROTO::linuxDma.reset();
return;
}
mainDevice = *dev;
auto fmts = g_pHyprOpenGL->getDRMFormats();
SDMABufTranche tranche = {
.device = *dev,
.formats = fmts,
};
std::vector<SDMABufTranche> tches;
tches.push_back(tranche);
defaultFeedback = std::make_unique<CCompiledDMABUFFeedback>(*dev, tches);
drmDevice* device = nullptr;
if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) {
LOGM(ERR, "failed to get drm dev");
PROTO::linuxDma.reset();
return;
}
if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
const char* name = device->nodes[DRM_NODE_RENDER];
mainDeviceFD = open(name, O_RDWR | O_CLOEXEC);
drmFreeDevice(&device);
if (mainDeviceFD < 0) {
LOGM(ERR, "failed to open drm dev");
PROTO::linuxDma.reset();
return;
}
} else {
LOGM(ERR, "DRM device {} has no render node!!", device->nodes[DRM_NODE_PRIMARY]);
drmFreeDevice(&device);
}
});
}
CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() {
if (mainDeviceFD >= 0)
close(mainDeviceFD);
}
void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CLinuxDMABUFResource>(makeShared<CZwpLinuxDmabufV1>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFResource* resource) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
}
void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFFeedbackResource* resource) {
std::erase_if(m_vFeedbacks, [&](const auto& other) { return other.get() == resource; });
}
void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resource) {
std::erase_if(m_vParams, [&](const auto& other) { return other.get() == resource; });
}
void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) {
std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; });
}

View file

@ -0,0 +1,138 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "wayland.hpp"
#include "linux-dmabuf-v1.hpp"
#include "../helpers/signal/Signal.hpp"
class CDMABuffer;
struct SDRMFormat;
struct SDMABUFAttrs;
class CWLSurfaceResource;
class CLinuxDMABuffer {
public:
CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs);
~CLinuxDMABuffer();
bool good();
private:
SP<CDMABuffer> buffer;
struct {
CHyprSignalListener bufferResourceDestroy;
} listeners;
friend class CLinuxDMABBUFParamsResource;
};
#pragma pack(push, 1)
struct SDMABUFFeedbackTableEntry {
uint32_t fmt = 0;
char pad[4];
uint64_t modifier = 0;
};
#pragma pack(pop)
class SCompiledDMABUFTranche {
dev_t device = 0;
uint32_t flags = 0;
std::vector<uint16_t> indices;
};
struct SDMABufTranche {
dev_t device = 0;
uint32_t flags = 0;
std::vector<SDRMFormat> formats;
};
class CCompiledDMABUFFeedback {
public:
CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches);
~CCompiledDMABUFFeedback();
dev_t mainDevice = 0;
int tableFD = -1;
size_t tableLen = 0;
std::vector<std::pair<uint32_t, uint64_t>> tranches;
};
class CLinuxDMABBUFParamsResource {
public:
CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParamsV1> resource_);
~CLinuxDMABBUFParamsResource();
bool good();
void create(uint32_t id); // 0 means not immed
SP<SDMABUFAttrs> attrs;
WP<CLinuxDMABuffer> createdBuffer;
bool used = false;
private:
SP<CZwpLinuxBufferParamsV1> resource;
bool verify();
bool commence();
};
class CLinuxDMABUFFeedbackResource {
public:
CLinuxDMABUFFeedbackResource(SP<CZwpLinuxDmabufFeedbackV1> resource_, SP<CWLSurfaceResource> surface_);
~CLinuxDMABUFFeedbackResource();
bool good();
SP<CWLSurfaceResource> surface; // optional, for surface feedbacks
private:
SP<CZwpLinuxDmabufFeedbackV1> resource;
};
class CLinuxDMABUFResource {
public:
CLinuxDMABUFResource(SP<CZwpLinuxDmabufV1> resource_);
bool good();
void sendMods();
private:
SP<CZwpLinuxDmabufV1> resource;
};
class CLinuxDMABufV1Protocol : public IWaylandProtocol {
public:
CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name);
~CLinuxDMABufV1Protocol();
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
private:
void destroyResource(CLinuxDMABUFResource* resource);
void destroyResource(CLinuxDMABUFFeedbackResource* resource);
void destroyResource(CLinuxDMABBUFParamsResource* resource);
void destroyResource(CLinuxDMABuffer* resource);
//
std::vector<SP<CLinuxDMABUFResource>> m_vManagers;
std::vector<SP<CLinuxDMABUFFeedbackResource>> m_vFeedbacks;
std::vector<SP<CLinuxDMABBUFParamsResource>> m_vParams;
std::vector<SP<CLinuxDMABuffer>> m_vBuffers;
UP<CCompiledDMABUFFeedback> defaultFeedback;
dev_t mainDevice;
int mainDeviceFD = -1;
friend class CLinuxDMABUFResource;
friend class CLinuxDMABUFFeedbackResource;
friend class CLinuxDMABBUFParamsResource;
friend class CLinuxDMABuffer;
};
namespace PROTO {
inline UP<CLinuxDMABufV1Protocol> linuxDma;
};

133
src/protocols/MesaDRM.cpp Normal file
View file

@ -0,0 +1,133 @@
#include "MesaDRM.hpp"
#include <algorithm>
#include <xf86drm.h>
#include "../Compositor.hpp"
#include <wlr/render/drm_format_set.h>
#include "types/WLBuffer.hpp"
#define LOGM PROTO::mesaDRM->protoLog
CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) {
LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes);
for (int i = 0; i < attrs_.planes; ++i) {
LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]);
}
buffer = makeShared<CDMABuffer>(id, client, attrs_);
buffer->resource->buffer = buffer;
listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) {
listeners.bufferResourceDestroy.reset();
PROTO::mesaDRM->destroyResource(this);
});
if (!buffer->success)
LOGM(ERR, "Possibly compositor bug: buffer failed to create");
}
CMesaDRMBufferResource::~CMesaDRMBufferResource() {
if (buffer && buffer->resource)
buffer->resource->sendRelease();
buffer.reset();
listeners.bufferResourceDestroy.reset();
}
bool CMesaDRMBufferResource::good() {
return buffer && buffer->good();
}
CMesaDRMResource::CMesaDRMResource(SP<CWlDrm> resource_) : resource(resource_) {
if (!good())
return;
resource->setOnDestroy([this](CWlDrm* r) { PROTO::mesaDRM->destroyResource(this); });
resource->setAuthenticate([this](CWlDrm* r, uint32_t token) {
// we don't need this
resource->sendAuthenticated();
});
resource->setCreateBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, uint32_t) { r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead"); });
resource->setCreatePlanarBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) {
r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead");
});
resource->setCreatePrimeBuffer(
[this](CWlDrm* r, uint32_t id, int32_t nameFd, int32_t w, int32_t h, uint32_t fmt, int32_t off0, int32_t str0, int32_t off1, int32_t str1, int32_t off2, int32_t str2) {
if (off0 < 0 || w <= 0 || h <= 0) {
r->error(WL_DRM_ERROR_INVALID_FORMAT, "Invalid w, h, or offset");
return;
}
SDMABUFAttrs attrs;
attrs.success = true;
attrs.size = {w, h};
attrs.modifier = DRM_FORMAT_MOD_INVALID;
attrs.planes = 1;
attrs.offsets[0] = off0;
attrs.strides[0] = str0;
attrs.fds[0] = nameFd;
attrs.format = fmt;
const auto RESOURCE = PROTO::mesaDRM->m_vBuffers.emplace_back(makeShared<CMesaDRMBufferResource>(id, resource->client(), attrs));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::mesaDRM->m_vBuffers.pop_back();
return;
}
// append instance so that buffer knows its owner
RESOURCE->buffer->resource->buffer = RESOURCE->buffer;
});
resource->sendDevice(PROTO::mesaDRM->nodeName.c_str());
resource->sendCapabilities(WL_DRM_CAPABILITY_PRIME);
auto fmts = g_pHyprOpenGL->getDRMFormats();
for (auto& fmt : fmts) {
resource->sendFormat(fmt.format);
}
}
bool CMesaDRMResource::good() {
return resource->resource();
}
CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
drmDevice* dev = nullptr;
int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
if (drmGetDevice2(drmFD, 0, &dev) != 0) {
LOGM(ERR, "Failed to get device");
PROTO::mesaDRM.reset();
return;
}
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
nodeName = dev->nodes[DRM_NODE_RENDER];
} else {
ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY));
LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]);
nodeName = dev->nodes[DRM_NODE_PRIMARY];
}
drmFreeDevice(&dev);
}
void CMesaDRMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CMesaDRMResource>(makeShared<CWlDrm>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CMesaDRMProtocol::destroyResource(CMesaDRMResource* resource) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
}
void CMesaDRMProtocol::destroyResource(CMesaDRMBufferResource* resource) {
std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; });
}

60
src/protocols/MesaDRM.hpp Normal file
View file

@ -0,0 +1,60 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "wayland-drm.hpp"
#include "types/Buffer.hpp"
#include "types/DMABuffer.hpp"
class CMesaDRMBufferResource {
public:
CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs);
~CMesaDRMBufferResource();
bool good();
private:
SP<CDMABuffer> buffer;
struct {
CHyprSignalListener bufferResourceDestroy;
} listeners;
friend class CMesaDRMResource;
};
class CMesaDRMResource {
public:
CMesaDRMResource(SP<CWlDrm> resource_);
bool good();
private:
SP<CWlDrm> resource;
};
class CMesaDRMProtocol : public IWaylandProtocol {
public:
CMesaDRMProtocol(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 destroyResource(CMesaDRMResource* resource);
void destroyResource(CMesaDRMBufferResource* resource);
//
std::vector<SP<CMesaDRMResource>> m_vManagers;
std::vector<SP<CMesaDRMBufferResource>> m_vBuffers;
std::string nodeName = "";
friend class CMesaDRMResource;
friend class CMesaDRMBufferResource;
};
namespace PROTO {
inline UP<CMesaDRMProtocol> mesaDRM;
};

View file

@ -1,5 +1,6 @@
#include "OutputPower.hpp"
#include "../Compositor.hpp"
#include "core/Output.hpp"
#define LOGM PROTO::outputPower->protoLog
@ -61,15 +62,15 @@ void COutputPowerProtocol::destroyOutputPower(COutputPower* power) {
void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uint32_t id, wl_resource* output) {
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output));
const auto OUTPUT = CWLOutputResource::fromResource(output);
if (!PMONITOR) {
if (!OUTPUT) {
pMgr->error(0, "Invalid output resource");
return;
}
const auto CLIENT = pMgr->client();
const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique<COutputPower>(makeShared<CZwlrOutputPowerV1>(CLIENT, pMgr->version(), id), PMONITOR)).get();
const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique<COutputPower>(makeShared<CZwlrOutputPowerV1>(CLIENT, pMgr->version(), id), OUTPUT->monitor.get())).get();
if (!RESOURCE->good()) {
pMgr->noMemory();

View file

@ -3,10 +3,11 @@
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../managers/SeatManager.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::constraints->protoLog
CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) :
CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) :
resourceL(resource_), locked(true) {
if (!resource_->resource())
return;
@ -14,13 +15,13 @@ CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_su
resource_->setOnDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
resource_->setDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
pHLSurface = CWLSurface::surfaceFromWlr(surf);
pHLSurface = CWLSurface::fromResource(surf);
if (!pHLSurface)
return;
if (region_)
region.set(wlr_region_from_resource(region_));
region.set(CWLRegionResource::fromResource(region_)->region);
resource_->setSetRegion([this](CZwpLockedPointerV1* p, wl_resource* region) { onSetRegion(region); });
resource_->setSetCursorPositionHint([this](CZwpLockedPointerV1* p, wl_fixed_t x, wl_fixed_t y) {
@ -45,7 +46,7 @@ CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_su
sharedConstructions();
}
CPointerConstraint::CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) :
CPointerConstraint::CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) :
resourceC(resource_), locked(false) {
if (!resource_->resource())
return;
@ -53,13 +54,13 @@ CPointerConstraint::CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, wlr_
resource_->setOnDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
resource_->setDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
pHLSurface = CWLSurface::surfaceFromWlr(surf);
pHLSurface = CWLSurface::fromResource(surf);
if (!pHLSurface)
return;
if (region_)
region.set(wlr_region_from_resource(region_));
region.set(CWLRegionResource::fromResource(region_)->region);
resource_->setSetRegion([this](CZwpConfinedPointerV1* p, wl_resource* region) { onSetRegion(region); });
@ -79,7 +80,7 @@ CPointerConstraint::~CPointerConstraint() {
void CPointerConstraint::sharedConstructions() {
if (pHLSurface) {
listeners.destroySurface = pHLSurface->events.destroy.registerListener([this](std::any d) {
pHLSurface = nullptr;
pHLSurface.reset();
if (active)
deactivate();
@ -92,7 +93,7 @@ void CPointerConstraint::sharedConstructions() {
cursorPosOnActivate = g_pInputManager->getMouseCoordsInternal();
if (g_pCompositor->m_pLastFocus == pHLSurface->wlr())
if (g_pCompositor->m_pLastFocus == pHLSurface->resource())
activate();
}
@ -126,10 +127,10 @@ void CPointerConstraint::activate() {
return;
// TODO: hack, probably not a super duper great idea
if (g_pSeatManager->state.pointerFocus != pHLSurface->wlr()) {
if (g_pSeatManager->state.pointerFocus != pHLSurface->resource()) {
const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal();
const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{};
g_pSeatManager->setPointerFocus(pHLSurface->wlr(), LOCAL);
g_pSeatManager->setPointerFocus(pHLSurface->resource(), LOCAL);
}
if (locked)
@ -152,15 +153,15 @@ void CPointerConstraint::onSetRegion(wl_resource* wlRegion) {
return;
}
const auto REGION = wlr_region_from_resource(wlRegion);
const auto REGION = region.set(CWLRegionResource::fromResource(wlRegion)->region);
region.set(REGION);
positionHint = region.closestPoint(positionHint);
g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss
}
CWLSurface* CPointerConstraint::owner() {
return pHLSurface;
SP<CWLSurface> CPointerConstraint::owner() {
return pHLSurface.lock();
}
CRegion CPointerConstraint::logicConstraintRegion() {
@ -241,7 +242,7 @@ void CPointerConstraintsProtocol::onLockPointer(CZwpPointerConstraintsV1* pMgr,
zwpPointerConstraintsV1Lifetime lifetime) {
const auto CLIENT = pMgr->client();
const auto RESOURCE = m_vConstraints.emplace_back(
makeShared<CPointerConstraint>(makeShared<CZwpLockedPointerV1>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime));
makeShared<CPointerConstraint>(makeShared<CZwpLockedPointerV1>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), region, lifetime));
onNewConstraint(RESOURCE, pMgr);
}
@ -250,7 +251,7 @@ void CPointerConstraintsProtocol::onConfinePointer(CZwpPointerConstraintsV1* pMg
zwpPointerConstraintsV1Lifetime lifetime) {
const auto CLIENT = pMgr->client();
const auto RESOURCE = m_vConstraints.emplace_back(
makeShared<CPointerConstraint>(makeShared<CZwpConfinedPointerV1>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime));
makeShared<CPointerConstraint>(makeShared<CZwpConfinedPointerV1>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), region, lifetime));
onNewConstraint(RESOURCE, pMgr);
}

View file

@ -12,31 +12,32 @@
#include "../helpers/signal/Listener.hpp"
class CWLSurface;
class CWLSurfaceResource;
class CPointerConstraint {
public:
CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_surface* surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime);
CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, wlr_surface* surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime);
CPointerConstraint(SP<CZwpLockedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime);
CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime);
~CPointerConstraint();
bool good();
bool good();
void deactivate();
void activate();
bool isActive();
void deactivate();
void activate();
bool isActive();
CWLSurface* owner();
SP<CWLSurface> owner();
CRegion logicConstraintRegion();
bool isLocked();
Vector2D logicPositionHint();
CRegion logicConstraintRegion();
bool isLocked();
Vector2D logicPositionHint();
private:
SP<CZwpLockedPointerV1> resourceL;
SP<CZwpConfinedPointerV1> resourceC;
wl_client* pClient = nullptr;
CWLSurface* pHLSurface = nullptr;
WP<CWLSurface> pHLSurface;
CRegion region;
bool hintSet = false;

View file

@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "core/Seat.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::pointerGestures->protoLog
@ -116,7 +117,7 @@ void CPointerGesturesProtocol::swipeBegin(uint32_t timeMs, uint32_t fingers) {
if (sw->resource->client() != FOCUSEDCLIENT)
continue;
sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers);
sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers);
}
}
@ -162,7 +163,7 @@ void CPointerGesturesProtocol::pinchBegin(uint32_t timeMs, uint32_t fingers) {
if (sw->resource->client() != FOCUSEDCLIENT)
continue;
sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers);
sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers);
}
}
@ -208,7 +209,7 @@ void CPointerGesturesProtocol::holdBegin(uint32_t timeMs, uint32_t fingers) {
if (sw->resource->client() != FOCUSEDCLIENT)
continue;
sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers);
sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers);
}
}

View file

@ -2,10 +2,11 @@
#include <algorithm>
#include "../helpers/Monitor.hpp"
#include "../managers/HookSystemManager.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::presentation->protoLog
CQueuedPresentationData::CQueuedPresentationData(wlr_surface* surf) : surface(surf) {
CQueuedPresentationData::CQueuedPresentationData(SP<CWLSurfaceResource> surf) : surface(surf) {
;
}
@ -25,7 +26,7 @@ void CQueuedPresentationData::discarded() {
wasPresented = false;
}
CPresentationFeedback::CPresentationFeedback(SP<CWpPresentationFeedback> resource_, wlr_surface* surf) : resource(resource_), surface(surf) {
CPresentationFeedback::CPresentationFeedback(SP<CWpPresentationFeedback> resource_, SP<CWLSurfaceResource> surf) : resource(resource_), surface(surf) {
if (!good())
return;
@ -69,7 +70,7 @@ void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespe
CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PMONITOR = std::any_cast<CMonitor*>(param);
std::erase_if(m_vQueue, [PMONITOR, this](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; });
std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; });
});
}
@ -92,7 +93,8 @@ void CPresentationProtocol::destroyResource(CPresentationFeedback* feedback) {
void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* surf, uint32_t id) {
const auto CLIENT = pMgr->client();
const auto RESOURCE =
m_vFeedbacks.emplace_back(makeShared<CPresentationFeedback>(makeShared<CWpPresentationFeedback>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get();
m_vFeedbacks.emplace_back(makeShared<CPresentationFeedback>(makeShared<CWpPresentationFeedback>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf)))
.get();
if (!RESOURCE->good()) {
pMgr->noMemory();
@ -116,8 +118,8 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint
}
}
std::erase_if(m_vFeedbacks, [pMonitor, this](const auto& other) { return !other->surface || other->done; });
std::erase_if(m_vQueue, [pMonitor, this](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; });
std::erase_if(m_vFeedbacks, [](const auto& other) { return !other->surface || other->done; });
std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; });
}
void CPresentationProtocol::queueData(SP<CQueuedPresentationData> data) {

View file

@ -7,10 +7,11 @@
#include "presentation-time.hpp"
class CMonitor;
class CWLSurfaceResource;
class CQueuedPresentationData {
public:
CQueuedPresentationData(wlr_surface* surf);
CQueuedPresentationData(SP<CWLSurfaceResource> surf);
void setPresentationType(bool zeroCopy);
void attachMonitor(CMonitor* pMonitor);
@ -19,10 +20,10 @@ class CQueuedPresentationData {
void discarded();
private:
bool wasPresented = false;
bool zeroCopy = false;
CMonitor* pMonitor = nullptr;
wlr_surface* surface = nullptr; // READ-ONLY
bool wasPresented = false;
bool zeroCopy = false;
CMonitor* pMonitor = nullptr;
WP<CWLSurfaceResource> surface;
DYNLISTENER(destroySurface);
@ -32,7 +33,7 @@ class CQueuedPresentationData {
class CPresentationFeedback {
public:
CPresentationFeedback(SP<CWpPresentationFeedback> resource_, wlr_surface* surf);
CPresentationFeedback(SP<CWpPresentationFeedback> resource_, SP<CWLSurfaceResource> surf);
bool good();
@ -40,8 +41,8 @@ class CPresentationFeedback {
private:
SP<CWpPresentationFeedback> resource;
wlr_surface* surface = nullptr; // READ-ONLY
bool done = false;
WP<CWLSurfaceResource> surface;
bool done = false;
friend class CPresentationProtocol;
};

View file

@ -2,11 +2,13 @@
#include "../Compositor.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../managers/PointerManager.hpp"
#include "core/Output.hpp"
#include "types/WLBuffer.hpp"
#include "types/Buffer.hpp"
#include "../helpers/Format.hpp"
#include <algorithm>
#include "ToplevelExportWlrFuncs.hpp"
#define SCREENCOPY_VERSION 3
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
@ -202,8 +204,8 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; });
wl_resource_set_user_data(frame->resource, nullptr);
if (frame->buffer && frame->buffer->n_locks > 0)
wlr_buffer_unlock(frame->buffer);
if (frame->buffer && frame->buffer->locked())
frame->buffer->unlock();
removeClient(frame->client, force);
m_lFrames.remove(*frame);
}
@ -214,7 +216,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
const auto PFRAME = &m_lFrames.emplace_back();
PFRAME->overlayCursor = !!overlay_cursor;
PFRAME->resource = wl_resource_create(client, &zwlr_screencopy_frame_v1_interface, wl_resource_get_version(resource), frame);
PFRAME->pMonitor = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output));
PFRAME->pMonitor = CWLOutputResource::fromResource(output)->monitor.get();
if (!PFRAME->pMonitor) {
Debug::log(ERR, "client requested sharing of a monitor that doesnt exist");
@ -256,7 +258,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
return;
}
const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat);
const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat);
if (!PSHMINFO) {
Debug::log(ERR, "No pixel format supported by renderer in capture output");
zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
@ -279,9 +281,9 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round();
PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w);
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
if (wl_resource_get_version(resource) >= 3) {
if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) {
@ -307,7 +309,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
return;
}
const auto PBUFFER = wlr_buffer_try_from_resource(buffer);
const auto PBUFFER = CWLBufferResource::fromResource(buffer);
if (!PBUFFER) {
Debug::log(ERR, "[sc] invalid buffer in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
@ -315,7 +317,9 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
return;
}
if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) {
PBUFFER->buffer->lock();
if (PBUFFER->buffer->size != PFRAME->box.size()) {
Debug::log(ERR, "[sc] invalid dimensions in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
removeFrame(PFRAME);
@ -329,28 +333,22 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
return;
}
wlr_dmabuf_attributes dmabufAttrs;
void* wlrBufferAccessData;
uint32_t wlrBufferAccessFormat;
size_t wlrBufferAccessStride;
if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) {
PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) {
PFRAME->bufferDMA = true;
if (dmabufAttrs.format != PFRAME->dmabufFormat) {
if (attrs.format != PFRAME->dmabufFormat) {
Debug::log(ERR, "[sc] invalid buffer dma format in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME);
return;
}
} else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) {
wlr_buffer_end_data_ptr_access(PBUFFER);
if (wlrBufferAccessFormat != PFRAME->shmFormat) {
} else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) {
if (attrs.format != PFRAME->shmFormat) {
Debug::log(ERR, "[sc] invalid buffer shm format in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME);
return;
} else if ((int)wlrBufferAccessStride != PFRAME->shmStride) {
} else if ((int)attrs.stride != PFRAME->shmStride) {
Debug::log(ERR, "[sc] invalid buffer shm stride in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
removeFrame(PFRAME);
@ -363,7 +361,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
return;
}
PFRAME->buffer = PBUFFER;
PFRAME->buffer = PBUFFER->buffer;
m_vFramesAwaitingWrite.emplace_back(PFRAME);
@ -432,7 +430,7 @@ void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) {
clock_gettime(CLOCK_MONOTONIC, &now);
uint32_t flags = 0;
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
if (frame->bufferDMA) {
if (!copyFrameDmabuf(frame)) {
Debug::log(ERR, "[sc] dmabuf copy failed in {:x}", (uintptr_t)frame);
zwlr_screencopy_frame_v1_send_failed(frame->resource);
@ -471,7 +469,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
// std::clamp(RECT.x2 - RECT.x1, 0, frame->buffer->width - RECT.x1), std::clamp(RECT.y2 - RECT.y1, 0, frame->buffer->height - RECT.y1));
// }
zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->width, frame->buffer->height);
zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->size.x, frame->buffer->size.y);
}
bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
@ -479,13 +477,10 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
if (!sourceTex)
return false;
void* data;
uint32_t format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) {
wlr_texture_destroy(sourceTex);
return false;
}
auto TEXTURE = makeShared<CTexture>(sourceTex);
auto shm = frame->buffer->shm();
auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
@ -496,14 +491,13 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) {
wlr_texture_destroy(sourceTex);
wlr_buffer_end_data_ptr_access(frame->buffer);
return false;
}
CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y});
g_pHyprOpenGL->setMonitorTransformEnabled(true);
g_pHyprOpenGL->setRenderModifEnabled(false);
g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1);
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
g_pHyprOpenGL->setRenderModifEnabled(true);
g_pHyprOpenGL->setMonitorTransformEnabled(false);
@ -513,14 +507,15 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
glBindFramebuffer(GL_FRAMEBUFFER, fb.m_iFb);
#endif
const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format);
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
if (!PFORMAT) {
g_pHyprRenderer->endRender();
wlr_texture_destroy(sourceTex);
wlr_buffer_end_data_ptr_access(frame->buffer);
return false;
}
auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA;
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
g_pHyprRenderer->endRender();
@ -530,21 +525,20 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
glPixelStorei(GL_PACK_ALIGNMENT, 1);
const wlr_pixel_format_info* drmFmtWlr = drm_get_pixel_format_info(format);
uint32_t packStride = pixel_format_info_min_stride(drmFmtWlr, frame->box.w);
const auto drmFmt = FormatUtils::getPixelFormatFromDRM(shm.format);
uint32_t packStride = FormatUtils::minStride(drmFmt, frame->box.w);
if (packStride == stride) {
glReadPixels(0, 0, frame->box.w, frame->box.h, PFORMAT->glFormat, PFORMAT->glType, data);
if (packStride == (uint32_t)shm.stride) {
glReadPixels(0, 0, frame->box.w, frame->box.h, glFormat, PFORMAT->glType, pixelData);
} else {
for (size_t i = 0; i < frame->box.h; ++i) {
uint32_t y = i;
glReadPixels(0, y, frame->box.w, 1, PFORMAT->glFormat, PFORMAT->glType, ((unsigned char*)data) + i * stride);
glReadPixels(0, y, frame->box.w, 1, glFormat, PFORMAT->glType, ((unsigned char*)pixelData) + i * shm.stride);
}
}
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
wlr_buffer_end_data_ptr_access(frame->buffer);
wlr_texture_destroy(sourceTex);
return true;
@ -555,9 +549,11 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
if (!sourceTex)
return false;
auto TEXTURE = makeShared<CTexture>(sourceTex);
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer, nullptr, true))
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true))
return false;
CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}
@ -565,7 +561,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
.transform(wlr_output_transform_invert(frame->pMonitor->output->transform), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
g_pHyprOpenGL->setMonitorTransformEnabled(true);
g_pHyprOpenGL->setRenderModifEnabled(false);
g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1);
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
g_pHyprOpenGL->setRenderModifEnabled(true);
g_pHyprOpenGL->setMonitorTransformEnabled(false);

View file

@ -10,6 +10,7 @@
#include "../managers/eventLoop/EventLoopTimer.hpp"
class CMonitor;
class IWLBuffer;
enum eClientOwners {
CLIENT_SCREENCOPY = 0,
@ -53,9 +54,9 @@ struct SScreencopyFrame {
bool withDamage = false;
bool lockedSWCursors = false;
wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM;
bool bufferDMA = false;
wlr_buffer* buffer = nullptr;
WP<IWLBuffer> buffer;
CMonitor* pMonitor = nullptr;
PHLWINDOWREF pWindow;

View file

@ -1,8 +1,9 @@
#include "ServerDecorationKDE.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::serverDecorationKDE->protoLog
CServerDecorationKDE::CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, wlr_surface* surf) : resource(resource_) {
CServerDecorationKDE::CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, SP<CWLSurfaceResource> surf) : resource(resource_) {
if (!good())
return;
@ -42,7 +43,8 @@ void CServerDecorationKDEProtocol::destroyResource(CServerDecorationKDE* hayperl
void CServerDecorationKDEProtocol::createDecoration(COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* surf) {
const auto CLIENT = pMgr->client();
const auto RESOURCE =
m_vDecos.emplace_back(std::make_unique<CServerDecorationKDE>(makeShared<COrgKdeKwinServerDecoration>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get();
m_vDecos.emplace_back(std::make_unique<CServerDecorationKDE>(makeShared<COrgKdeKwinServerDecoration>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf)))
.get();
if (!RESOURCE->good()) {
pMgr->noMemory();

View file

@ -6,9 +6,11 @@
#include "WaylandProtocol.hpp"
#include "kde-server-decoration.hpp"
class CWLSurfaceResource;
class CServerDecorationKDE {
public:
CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, wlr_surface* surf);
CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, SP<CWLSurfaceResource> surf);
bool good();

View file

@ -2,10 +2,12 @@
#include "../Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "FractionalScale.hpp"
#include "core/Compositor.hpp"
#include "core/Output.hpp"
#define LOGM PROTO::sessionLock->protoLog
CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_) :
CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, SP<CWLSurfaceResource> surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_) :
resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) {
if (!resource->resource())
return;
@ -21,45 +23,38 @@ CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_,
resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; });
hyprListener_surfaceCommit.initCallback(
&pSurface->events.commit,
[this](void* owner, void* data) {
if (pSurface->pending.buffer_width <= 0 || pSurface->pending.buffer_height <= 0) {
LOGM(ERR, "SessionLock attached a null buffer");
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached");
return;
}
listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) {
if (!pSurface->current.buffer) {
LOGM(ERR, "SessionLock attached a null buffer");
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached");
return;
}
if (!ackdConfigure) {
LOGM(ERR, "SessionLock committed without an ack");
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, "Committed surface before first ack");
return;
}
if (!ackdConfigure) {
LOGM(ERR, "SessionLock committed without an ack");
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, "Committed surface before first ack");
return;
}
if (committed)
events.commit.emit();
else {
wlr_surface_map(pSurface);
events.map.emit();
}
committed = true;
},
this, "SessionLockSurface");
if (committed)
events.commit.emit();
else {
pSurface->map();
events.map.emit();
}
committed = true;
});
hyprListener_surfaceDestroy.initCallback(
&pSurface->events.destroy,
[this](void* owner, void* data) {
LOGM(WARN, "SessionLockSurface object remains but surface is being destroyed???");
wlr_surface_unmap(pSurface);
hyprListener_surfaceCommit.removeCallback();
hyprListener_surfaceDestroy.removeCallback();
listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) {
LOGM(WARN, "SessionLockSurface object remains but surface is being destroyed???");
pSurface->unmap();
listeners.surfaceCommit.reset();
listeners.surfaceDestroy.reset();
if (g_pCompositor->m_pLastFocus == pSurface)
g_pCompositor->m_pLastFocus.reset();
if (g_pCompositor->m_pLastFocus == pSurface)
g_pCompositor->m_pLastFocus = nullptr;
pSurface = nullptr;
},
this, "SessionLockSurface");
pSurface.reset();
});
PROTO::fractional->sendScale(surface_, pMonitor_->scale);
@ -70,9 +65,9 @@ CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_,
CSessionLockSurface::~CSessionLockSurface() {
if (pSurface && pSurface->mapped)
wlr_surface_unmap(pSurface);
hyprListener_surfaceCommit.removeCallback();
hyprListener_surfaceDestroy.removeCallback();
pSurface->unmap();
listeners.surfaceCommit.reset();
listeners.surfaceDestroy.reset();
events.destroy.emit(); // just in case.
}
@ -93,8 +88,8 @@ CMonitor* CSessionLockSurface::monitor() {
return pMonitor;
}
wlr_surface* CSessionLockSurface::surface() {
return pSurface;
SP<CWLSurfaceResource> CSessionLockSurface::surface() {
return pSurface.lock();
}
CSessionLock::CSessionLock(SP<CExtSessionLockV1> resource_) : resource(resource_) {
@ -195,8 +190,8 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) {
void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id, wl_resource* surface, wl_resource* output) {
LOGM(LOG, "New sessionLockSurface with id {}", id);
auto PSURFACE = wlr_surface_from_resource(surface);
auto PMONITOR = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output));
auto PSURFACE = CWLSurfaceResource::fromResource(surface);
auto PMONITOR = CWLOutputResource::fromResource(output)->monitor.get();
SP<CSessionLock> sessionLock;
for (auto& l : m_vLocks) {

View file

@ -9,16 +9,17 @@
class CMonitor;
class CSessionLock;
class CWLSurfaceResource;
class CSessionLockSurface {
public:
CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_);
CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, SP<CWLSurfaceResource> surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_);
~CSessionLockSurface();
bool good();
bool inert();
CMonitor* monitor();
wlr_surface* surface();
bool good();
bool inert();
CMonitor* monitor();
SP<CWLSurfaceResource> surface();
struct {
CSignal map;
@ -29,7 +30,7 @@ class CSessionLockSurface {
private:
SP<CExtSessionLockSurfaceV1> resource;
WP<CSessionLock> sessionLock;
wlr_surface* pSurface = nullptr;
WP<CWLSurfaceResource> pSurface;
CMonitor* pMonitor = nullptr;
bool ackdConfigure = false;
@ -37,11 +38,10 @@ class CSessionLockSurface {
void sendConfigure();
DYNLISTENER(surfaceCommit);
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener monitorMode;
CHyprSignalListener surfaceCommit;
CHyprSignalListener surfaceDestroy;
} listeners;
};

View file

@ -1,10 +1,11 @@
#include "ShortcutsInhibit.hpp"
#include <algorithm>
#include "../Compositor.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::shortcutsInhibit->protoLog
CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, wlr_surface* surf) : resource(resource_), pSurface(surf) {
CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, SP<CWLSurfaceResource> surf) : resource(resource_), pSurface(surf) {
if (!resource->resource())
return;
@ -16,8 +17,8 @@ CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcut
resource->sendActive();
}
wlr_surface* CKeyboardShortcutsInhibitor::surface() {
return pSurface;
SP<CWLSurfaceResource> CKeyboardShortcutsInhibitor::surface() {
return pSurface.lock();
}
bool CKeyboardShortcutsInhibitor::good() {
@ -46,8 +47,8 @@ void CKeyboardShortcutsInhibitProtocol::destroyInhibitor(CKeyboardShortcutsInhib
}
void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* seat) {
wlr_surface* surf = wlr_surface_from_resource(surface);
const auto CLIENT = pMgr->client();
SP<CWLSurfaceResource> surf = CWLSurfaceResource::fromResource(surface);
const auto CLIENT = pMgr->client();
for (auto& in : m_vInhibitors) {
if (in->surface() != surf)

View file

@ -6,17 +6,19 @@
#include "WaylandProtocol.hpp"
#include "keyboard-shortcuts-inhibit-unstable-v1.hpp"
class CWLSurfaceResource;
class CKeyboardShortcutsInhibitor {
public:
CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, wlr_surface* surf);
CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, SP<CWLSurfaceResource> surf);
// read-only pointer, may be invalid
wlr_surface* surface();
bool good();
SP<CWLSurfaceResource> surface();
bool good();
private:
SP<CZwpKeyboardShortcutsInhibitorV1> resource;
wlr_surface* pSurface = nullptr;
WP<CWLSurfaceResource> pSurface;
};
class CKeyboardShortcutsInhibitProtocol : public IWaylandProtocol {

View file

@ -3,6 +3,7 @@
#include "../Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "core/Seat.hpp"
#include "core/Compositor.hpp"
#include <algorithm>
#define LOGM PROTO::tablet->protoLog
@ -160,11 +161,11 @@ CTabletToolV2Resource::CTabletToolV2Resource(SP<CZwpTabletToolV2> resource_, SP<
resource->setDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); });
resource->setOnDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); });
resource->setSetCursor([this](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) {
resource->setSetCursor([](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) {
if (!g_pSeatManager->state.pointerFocusResource || g_pSeatManager->state.pointerFocusResource->client() != r->client())
return;
g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{surf ? wlr_surface_from_resource(surf) : nullptr, {hot_x, hot_y}});
g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hot_x, hot_y}});
});
}
@ -448,7 +449,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() {
if (t->current) {
t->resource->sendProximityOut();
t->sendFrame();
t->lastSurf = nullptr;
t->lastSurf.reset();
}
t->resource->sendRemoved();
@ -545,9 +546,9 @@ void CTabletV2Protocol::down(SP<CTabletTool> tool) {
}
}
void CTabletV2Protocol::proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf) {
void CTabletV2Protocol::proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, SP<CWLSurfaceResource> surf) {
proximityOut(tool);
const auto CLIENT = wl_resource_get_client(surf->resource);
const auto CLIENT = surf->client();
SP<CTabletToolV2Resource> toolResource;
SP<CTabletV2Resource> tabletResource;
@ -587,7 +588,7 @@ void CTabletV2Protocol::proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wl
toolResource->lastSurf = surf;
auto serial = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(toolResource->resource->client()));
toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->resource);
toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->getResource()->resource());
toolResource->queueFrame();
LOGM(ERR, "proximityIn: found no resource to send enter");
@ -598,8 +599,8 @@ void CTabletV2Protocol::proximityOut(SP<CTabletTool> tool) {
if (t->tool != tool || !t->current)
continue;
t->current = false;
t->lastSurf = nullptr;
t->current = false;
t->lastSurf.reset();
t->resource->sendProximityOut();
t->sendFrame();
}

View file

@ -12,6 +12,7 @@ class CTabletTool;
class CTabletPad;
class CEventLoopTimer;
class CTabletSeat;
class CWLSurfaceResource;
class CTabletPadStripV2Resource {
public:
@ -112,19 +113,19 @@ class CTabletToolV2Resource {
CTabletToolV2Resource(SP<CZwpTabletToolV2> resource_, SP<CTabletTool> tool_, SP<CTabletSeat> seat_);
~CTabletToolV2Resource();
bool good();
void sendData();
void queueFrame();
void sendFrame(bool removeSource = true);
bool good();
void sendData();
void queueFrame();
void sendFrame(bool removeSource = true);
bool current = false;
wlr_surface* lastSurf = nullptr; // READ-ONLY
bool current = false;
WP<CWLSurfaceResource> lastSurf;
WP<CTabletTool> tool;
WP<CTabletSeat> seat;
wl_event_source* frameSource = nullptr;
WP<CTabletTool> tool;
WP<CTabletSeat> seat;
wl_event_source* frameSource = nullptr;
bool inert = false; // removed was sent
bool inert = false; // removed was sent
private:
SP<CZwpTabletToolV2> resource;
@ -180,7 +181,7 @@ class CTabletV2Protocol : public IWaylandProtocol {
void tilt(SP<CTabletTool> tool, const Vector2D& value);
void up(SP<CTabletTool> tool);
void down(SP<CTabletTool> tool);
void proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf);
void proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, SP<CWLSurfaceResource> surf);
void proximityOut(SP<CTabletTool> tool);
void buttonTool(SP<CTabletTool> tool, uint32_t button, uint32_t state);
void motion(SP<CTabletTool> tool, const Vector2D& value);

View file

@ -2,6 +2,7 @@
#include "../managers/ProtocolManager.hpp"
#include "../desktop/Window.hpp"
#include "../Compositor.hpp"
#include "core/Compositor.hpp"
CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P =
@ -13,15 +14,16 @@ void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_
RESOURCE->setOnDestroy([this](CWpTearingControlManagerV1* p) { this->onManagerResourceDestroy(p->resource()); });
RESOURCE->setDestroy([this](CWpTearingControlManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setGetTearingControl(
[this](CWpTearingControlManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetController(pMgr->client(), pMgr, id, wlr_surface_from_resource(surface)); });
RESOURCE->setGetTearingControl([this](CWpTearingControlManagerV1* pMgr, uint32_t id, wl_resource* surface) {
this->onGetController(pMgr->client(), pMgr, id, CWLSurfaceResource::fromResource(surface));
});
}
void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
}
void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, wlr_surface* surf) {
void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surf) {
const auto CONTROLLER = m_vTearingControllers.emplace_back(std::make_unique<CTearingControl>(makeShared<CWpTearingControlV1>(client, pMgr->version(), id), surf)).get();
if (!CONTROLLER->good()) {
@ -44,14 +46,14 @@ void CTearingControlProtocol::onWindowDestroy(PHLWINDOW pWindow) {
//
CTearingControl::CTearingControl(SP<CWpTearingControlV1> resource_, wlr_surface* surf_) : resource(resource_) {
CTearingControl::CTearingControl(SP<CWpTearingControlV1> resource_, SP<CWLSurfaceResource> surf_) : resource(resource_) {
resource->setData(this);
resource->setOnDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); });
resource->setDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); });
resource->setSetPresentationHint([this](CWpTearingControlV1* res, wpTearingControlV1PresentationHint hint) { this->onHint(hint); });
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_pWLSurface.wlr() == surf_) {
if (w->m_pWLSurface->resource() == surf_) {
pWindow = w;
break;
}

View file

@ -6,10 +6,11 @@
class CWindow;
class CTearingControlProtocol;
class CWLSurfaceResource;
class CTearingControl {
public:
CTearingControl(SP<CWpTearingControlV1> resource_, wlr_surface* surf_);
CTearingControl(SP<CWpTearingControlV1> resource_, SP<CWLSurfaceResource> surf_);
void onHint(wpTearingControlV1PresentationHint hint_);
@ -42,7 +43,7 @@ class CTearingControlProtocol : public IWaylandProtocol {
private:
void onManagerResourceDestroy(wl_resource* res);
void onControllerDestroy(CTearingControl* control);
void onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, wlr_surface* surf);
void onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surf);
void onWindowDestroy(PHLWINDOW pWindow);
//

View file

@ -1,6 +1,7 @@
#include "TextInputV1.hpp"
#include "../Compositor.hpp"
#include "core/Compositor.hpp"
#define TEXT_INPUT_VERSION 1
@ -168,7 +169,7 @@ void CTextInputV1ProtocolManager::handleActivate(wl_client* client, wl_resource*
return;
}
PTI->active = true;
PTI->pTextInput->onEnabled(wlr_surface_from_resource(surface));
PTI->pTextInput->onEnabled(CWLSurfaceResource::fromResource(surface));
}
void CTextInputV1ProtocolManager::handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat) {

View file

@ -1,5 +1,6 @@
#include "TextInputV3.hpp"
#include <algorithm>
#include "core/Compositor.hpp"
#define LOGM PROTO::textInputV3->protoLog
@ -66,12 +67,12 @@ CTextInputV3::~CTextInputV3() {
events.destroy.emit();
}
void CTextInputV3::enter(wlr_surface* surf) {
resource->sendEnter(surf->resource);
void CTextInputV3::enter(SP<CWLSurfaceResource> surf) {
resource->sendEnter(surf->getResource()->resource());
}
void CTextInputV3::leave(wlr_surface* surf) {
resource->sendLeave(surf->resource);
void CTextInputV3::leave(SP<CWLSurfaceResource> surf) {
resource->sendLeave(surf->getResource()->resource());
}
void CTextInputV3::preeditString(const std::string& text, int32_t cursorBegin, int32_t cursorEnd) {

View file

@ -9,13 +9,15 @@
#include "../helpers/signal/Signal.hpp"
#include "../helpers/Box.hpp"
class CWLSurfaceResource;
class CTextInputV3 {
public:
CTextInputV3(SP<CZwpTextInputV3> resource_);
~CTextInputV3();
void enter(wlr_surface* surf);
void leave(wlr_surface* surf);
void enter(SP<CWLSurfaceResource> surf);
void leave(SP<CWLSurfaceResource> surf);
void preeditString(const std::string& text, int32_t cursorBegin, int32_t cursorEnd);
void commitString(const std::string& text);
void deleteSurroundingText(uint32_t beforeLength, uint32_t afterLength);

View file

@ -2,11 +2,12 @@
#include "../Compositor.hpp"
#include "ForeignToplevelWlr.hpp"
#include "../managers/PointerManager.hpp"
#include "types/WLBuffer.hpp"
#include "types/Buffer.hpp"
#include "../helpers/Format.hpp"
#include <algorithm>
#include "ToplevelExportWlrFuncs.hpp"
#define TOPLEVEL_EXPORT_VERSION 2
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
@ -131,8 +132,8 @@ void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool f
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; });
wl_resource_set_user_data(frame->resource, nullptr);
if (frame->buffer && frame->buffer->n_locks > 0)
wlr_buffer_unlock(frame->buffer);
if (frame->buffer && frame->buffer->locked() > 0)
frame->buffer->unlock();
removeClient(frame->client, force);
m_lFrames.remove(*frame);
}
@ -184,7 +185,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou
return;
}
const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat);
const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat);
if (!PSHMINFO) {
Debug::log(ERR, "No pixel format supported by renderer in capture toplevel");
hyprland_toplevel_export_frame_v1_send_failed(resource);
@ -203,9 +204,9 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
PFRAME->box.transform(PMONITOR->transform, ow, oh).round();
PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w);
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) {
hyprland_toplevel_export_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height);
@ -238,14 +239,16 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r
return;
}
const auto PBUFFER = wlr_buffer_try_from_resource(buffer);
const auto PBUFFER = CWLBufferResource::fromResource(buffer);
if (!PBUFFER) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
removeFrame(PFRAME);
return;
}
if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) {
PBUFFER->buffer->lock();
if (PBUFFER->buffer->size != PFRAME->box.size()) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
removeFrame(PFRAME);
return;
@ -257,26 +260,20 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r
return;
}
wlr_dmabuf_attributes dmabufAttrs;
void* wlrBufferAccessData;
uint32_t wlrBufferAccessFormat;
size_t wlrBufferAccessStride;
if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) {
PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) {
PFRAME->bufferDMA = true;
if (dmabufAttrs.format != PFRAME->dmabufFormat) {
if (attrs.format != PFRAME->dmabufFormat) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME);
return;
}
} else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) {
wlr_buffer_end_data_ptr_access(PBUFFER);
if (wlrBufferAccessFormat != PFRAME->shmFormat) {
} else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) {
if (attrs.format != PFRAME->shmFormat) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME);
return;
} else if ((int)wlrBufferAccessStride != PFRAME->shmStride) {
} else if ((int)attrs.stride != PFRAME->shmStride) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
removeFrame(PFRAME);
return;
@ -287,7 +284,7 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r
return;
}
PFRAME->buffer = PBUFFER;
PFRAME->buffer = PBUFFER->buffer;
m_vFramesAwaitingWrite.emplace_back(PFRAME);
}
@ -338,7 +335,7 @@ void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) {
clock_gettime(CLOCK_MONOTONIC, &now);
uint32_t flags = 0;
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
if (frame->bufferDMA) {
if (!copyFrameDmabuf(frame, &now)) {
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
return;
@ -363,11 +360,8 @@ void CToplevelExportProtocolManager::sendDamage(SScreencopyFrame* frame) {
}
bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
void* data;
uint32_t format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride))
return false;
auto shm = frame->buffer->shm();
auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm
// render the client
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
@ -383,10 +377,8 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
g_pPointerManager->damageCursor(PMONITOR->self.lock());
}
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) {
wlr_buffer_end_data_ptr_access(frame->buffer);
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB))
return false;
}
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
@ -398,10 +390,9 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
if (frame->overlayCursor)
g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value());
const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format);
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
if (!PFORMAT) {
g_pHyprRenderer->endRender();
wlr_buffer_end_data_ptr_access(frame->buffer);
return false;
}
@ -418,9 +409,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, data);
wlr_buffer_end_data_ptr_access(frame->buffer);
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, pixelData);
if (frame->overlayCursor) {
g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock());
@ -435,7 +424,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer))
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock()))
return false;
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));

View file

@ -1,243 +0,0 @@
#include <GLES2/gl2ext.h>
#ifndef DRM_WLR_FUNCS
#define DRM_WLR_FUNCS
struct wlr_pixel_format_info {
uint32_t drm_format;
/* Equivalent of the format if it has an alpha channel,
* DRM_FORMAT_INVALID (0) if NA
*/
uint32_t opaque_substitute;
/* Bytes per block (including padding) */
uint32_t bytes_per_block;
/* Size of a block in pixels (zero for 1×1) */
uint32_t block_width, block_height;
/* True if the format has an alpha channel */
bool has_alpha;
};
static const struct wlr_pixel_format_info pixel_format_info[] = {
{
.drm_format = DRM_FORMAT_XRGB8888,
.bytes_per_block = 4,
},
{
.drm_format = DRM_FORMAT_ARGB8888,
.opaque_substitute = DRM_FORMAT_XRGB8888,
.bytes_per_block = 4,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR8888,
.bytes_per_block = 4,
},
{
.drm_format = DRM_FORMAT_ABGR8888,
.opaque_substitute = DRM_FORMAT_XBGR8888,
.bytes_per_block = 4,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGBX8888,
.bytes_per_block = 4,
},
{
.drm_format = DRM_FORMAT_RGBA8888,
.opaque_substitute = DRM_FORMAT_RGBX8888,
.bytes_per_block = 4,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_BGRX8888,
.bytes_per_block = 4,
},
{
.drm_format = DRM_FORMAT_BGRA8888,
.opaque_substitute = DRM_FORMAT_BGRX8888,
.bytes_per_block = 4,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_R8,
.bytes_per_block = 1,
},
{
.drm_format = DRM_FORMAT_GR88,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_RGB888,
.bytes_per_block = 3,
},
{
.drm_format = DRM_FORMAT_BGR888,
.bytes_per_block = 3,
},
{
.drm_format = DRM_FORMAT_RGBX4444,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_RGBA4444,
.opaque_substitute = DRM_FORMAT_RGBX4444,
.bytes_per_block = 2,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_BGRX4444,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_BGRA4444,
.opaque_substitute = DRM_FORMAT_BGRX4444,
.bytes_per_block = 2,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGBX5551,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_RGBA5551,
.opaque_substitute = DRM_FORMAT_RGBX5551,
.bytes_per_block = 2,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_BGRX5551,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_BGRA5551,
.opaque_substitute = DRM_FORMAT_BGRX5551,
.bytes_per_block = 2,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XRGB1555,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_ARGB1555,
.opaque_substitute = DRM_FORMAT_XRGB1555,
.bytes_per_block = 2,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGB565,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_BGR565,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_XRGB2101010,
.bytes_per_block = 4,
},
{
.drm_format = DRM_FORMAT_ARGB2101010,
.opaque_substitute = DRM_FORMAT_XRGB2101010,
.bytes_per_block = 4,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR2101010,
.bytes_per_block = 4,
},
{
.drm_format = DRM_FORMAT_ABGR2101010,
.opaque_substitute = DRM_FORMAT_XBGR2101010,
.bytes_per_block = 4,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR16161616F,
.bytes_per_block = 8,
},
{
.drm_format = DRM_FORMAT_ABGR16161616F,
.opaque_substitute = DRM_FORMAT_XBGR16161616F,
.bytes_per_block = 8,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR16161616,
.bytes_per_block = 8,
},
{
.drm_format = DRM_FORMAT_ABGR16161616,
.opaque_substitute = DRM_FORMAT_XBGR16161616,
.bytes_per_block = 8,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_YVYU,
.bytes_per_block = 4,
.block_width = 2,
.block_height = 1,
},
{
.drm_format = DRM_FORMAT_VYUY,
.bytes_per_block = 4,
.block_width = 2,
.block_height = 1,
},
};
static const size_t pixel_format_info_size = sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
static const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) {
for (size_t i = 0; i < pixel_format_info_size; ++i) {
if (pixel_format_info[i].drm_format == fmt) {
return &pixel_format_info[i];
}
}
return NULL;
}
/*static uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
switch (fmt) {
case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
default: return (uint32_t)fmt;
}
}*/
static enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
switch (fmt) {
case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888;
case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888;
default: return (enum wl_shm_format)fmt;
}
}
static uint32_t pixel_format_info_pixels_per_block(const struct wlr_pixel_format_info* info) {
uint32_t pixels = info->block_width * info->block_height;
return pixels > 0 ? pixels : 1;
}
static int32_t div_round_up(int32_t dividend, int32_t divisor) {
int32_t quotient = dividend / divisor;
if (dividend % divisor != 0) {
quotient++;
}
return quotient;
}
static int32_t pixel_format_info_min_stride(const wlr_pixel_format_info* fmt, int32_t width) {
int32_t pixels_per_block = (int32_t)pixel_format_info_pixels_per_block(fmt);
int32_t bytes_per_block = (int32_t)fmt->bytes_per_block;
if (width > INT32_MAX / bytes_per_block) {
wlr_log(WLR_DEBUG, "Invalid width %d (overflow)", width);
return 0;
}
return div_round_up(width * bytes_per_block, pixels_per_block);
}
#endif

View file

@ -0,0 +1,126 @@
#include "Viewporter.hpp"
#include "core/Compositor.hpp"
#include <algorithm>
#define LOGM PROTO::viewport->protoLog
CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) {
if (!good())
return;
resource->setDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); });
resource->setOnDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); });
resource->setSetDestination([this](CWpViewport* r, int32_t x, int32_t y) {
if (!surface) {
r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone");
return;
}
if (x == -1 && y == -1) {
surface->pending.viewport.hasDestination = false;
return;
}
if (x <= 0 || y <= 0) {
r->error(WP_VIEWPORT_ERROR_BAD_SIZE, "Size was <= 0");
return;
}
surface->pending.viewport.hasDestination = true;
surface->pending.viewport.destination = {x, y};
});
resource->setSetSource([this](CWpViewport* r, wl_fixed_t fx, wl_fixed_t fy, wl_fixed_t fw, wl_fixed_t fh) {
if (!surface) {
r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone");
return;
}
double x = wl_fixed_to_double(fx), y = wl_fixed_to_double(fy), w = wl_fixed_to_double(fw), h = wl_fixed_to_double(fh);
if (x == -1 && y == -1 && w == -1 && h == -1) {
surface->pending.viewport.hasSource = false;
return;
}
if (x < 0 || y < 0) {
r->error(WP_VIEWPORT_ERROR_BAD_SIZE, "Pos was < 0");
return;
}
surface->pending.viewport.hasSource = true;
surface->pending.viewport.source = {x, y, w, h};
});
}
CViewportResource::~CViewportResource() {
if (!surface)
return;
surface->pending.viewport.hasDestination = false;
surface->pending.viewport.hasSource = false;
}
bool CViewportResource::good() {
return resource->resource();
}
void CViewportResource::verify() {
if (!surface)
return;
if (surface->pending.viewport.hasSource) {
auto& src = surface->pending.viewport.source;
if (src.w + src.x > surface->pending.size.x || src.h + src.y > surface->pending.size.y) {
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
return;
}
}
}
CViewporterResource::CViewporterResource(SP<CWpViewporter> resource_) : resource(resource_) {
if (!good())
return;
resource->setDestroy([this](CWpViewporter* r) { PROTO::viewport->destroyResource(this); });
resource->setOnDestroy([this](CWpViewporter* r) { PROTO::viewport->destroyResource(this); });
resource->setGetViewport([](CWpViewporter* r, uint32_t id, wl_resource* surf) {
const auto RESOURCE = PROTO::viewport->m_vViewports.emplace_back(
makeShared<CViewportResource>(makeShared<CWpViewport>(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf)));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::viewport->m_vViewports.pop_back();
return;
}
});
}
bool CViewporterResource::good() {
return resource->resource();
}
CViewporterProtocol::CViewporterProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CViewporterProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CViewporterResource>(makeShared<CWpViewporter>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CViewporterProtocol::destroyResource(CViewporterResource* resource) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
}
void CViewporterProtocol::destroyResource(CViewportResource* resource) {
std::erase_if(m_vViewports, [&](const auto& other) { return other.get() == resource; });
}

View file

@ -0,0 +1,55 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "viewporter.hpp"
#include "../helpers/signal/Signal.hpp"
class CWLSurfaceResource;
class CViewportResource {
public:
CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceResource> surface_);
~CViewportResource();
bool good();
void verify();
WP<CWLSurfaceResource> surface;
private:
SP<CWpViewport> resource;
};
class CViewporterResource {
public:
CViewporterResource(SP<CWpViewporter> resource_);
bool good();
private:
SP<CWpViewporter> resource;
};
class CViewporterProtocol : public IWaylandProtocol {
public:
CViewporterProtocol(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 destroyResource(CViewporterResource* resource);
void destroyResource(CViewportResource* resource);
//
std::vector<SP<CViewporterResource>> m_vManagers;
std::vector<SP<CViewportResource>> m_vViewports;
friend class CViewporterResource;
friend class CViewportResource;
};
namespace PROTO {
inline UP<CViewporterProtocol> viewport;
};

View file

@ -10,6 +10,8 @@ static void displayDestroyInternal(struct wl_listener* listener, void* data) {
}
void IWaylandProtocol::onDisplayDestroy() {
wl_list_remove(&m_liDisplayDestroy.link);
wl_list_init(&m_liDisplayDestroy.link);
wl_global_destroy(m_pGlobal);
}
@ -30,3 +32,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co
IWaylandProtocol::~IWaylandProtocol() {
onDisplayDestroy();
}
void IWaylandProtocol::removeGlobal() {
wl_global_remove(m_pGlobal);
}

View file

@ -14,9 +14,10 @@
class IWaylandProtocol {
public:
IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name);
~IWaylandProtocol();
virtual ~IWaylandProtocol();
virtual void onDisplayDestroy();
virtual void removeGlobal();
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0;

View file

@ -1,6 +1,7 @@
#include "XDGActivation.hpp"
#include "../managers/TokenManager.hpp"
#include "../Compositor.hpp"
#include "core/Compositor.hpp"
#include <algorithm>
#define LOGM PROTO::activation->protoLog
@ -79,8 +80,8 @@ void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t
// remove token. It's been now spent.
m_vSentTokens.erase(TOKEN);
wlr_surface* surf = wlr_surface_from_resource(surface);
const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf);
SP<CWLSurfaceResource> surf = CWLSurfaceResource::fromResource(surface);
const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf);
if (!PWINDOW) {
LOGM(WARN, "activate event for non-window or gone surface with token {}, ignoring", token);

View file

@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../xwayland/XWayland.hpp"
#include "core/Output.hpp"
#define OUTPUT_MANAGER_VERSION 3
#define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3
@ -48,9 +49,9 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver
}
void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) {
const auto OUTPUT = wlr_output_from_resource(outputResource);
const auto OUTPUT = CWLOutputResource::fromResource(outputResource);
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT);
const auto PMONITOR = OUTPUT->monitor.get();
const auto CLIENT = mgr->client();

View file

@ -3,6 +3,7 @@
#include "../Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "core/Seat.hpp"
#include "core/Compositor.hpp"
#define LOGM PROTO::xdgShell->protoLog
@ -288,7 +289,8 @@ void CXDGToplevelResource::close() {
resource->sendClose();
}
CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, wlr_surface* surface_) : owner(owner_), surface(surface_), resource(resource_) {
CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, SP<CWLSurfaceResource> surface_) :
owner(owner_), surface(surface_), resource(resource_) {
if (!good())
return;
@ -307,56 +309,50 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
PROTO::xdgShell->destroyResource(this);
});
hyprListener_surfaceDestroy.initCallback(
&surface->events.destroy,
[this](void* owner, void* data) {
LOGM(WARN, "wl_surface destroyed before its xdg_surface role object");
hyprListener_surfaceDestroy.removeCallback();
hyprListener_surfaceCommit.removeCallback();
listeners.surfaceDestroy = surface->events.destroy.registerListener([this](std::any d) {
LOGM(WARN, "wl_surface destroyed before its xdg_surface role object");
listeners.surfaceDestroy.reset();
listeners.surfaceCommit.reset();
if (mapped)
events.unmap.emit();
if (mapped)
events.unmap.emit();
mapped = false;
surface = nullptr;
events.destroy.emit();
},
nullptr, "CXDGSurfaceResource");
mapped = false;
surface.reset();
events.destroy.emit();
});
hyprListener_surfaceCommit.initCallback(
&surface->events.commit,
[this](void* owner, void* data) {
current = pending;
listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) {
current = pending;
if (toplevel)
toplevel->current = toplevel->pending;
if (initialCommit && surface->pending.buffer) {
resource->error(-1, "Buffer attached before initial commit");
return;
}
if (surface->current.buffer && !mapped) {
// this forces apps to not draw CSD.
if (toplevel)
toplevel->current = toplevel->pending;
toplevel->setMaximized(true);
if (initialCommit && surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) {
resource->error(-1, "Buffer attached before initial commit");
return;
}
mapped = true;
surface->map();
events.map.emit();
return;
}
if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) {
// this forces apps to not draw CSD.
if (toplevel)
toplevel->setMaximized(true);
if (!surface->current.buffer && mapped) {
mapped = false;
surface->unmap();
events.unmap.emit();
return;
}
mapped = true;
wlr_surface_map(surface);
events.map.emit();
return;
}
if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) {
mapped = false;
wlr_surface_unmap(surface);
events.unmap.emit();
return;
}
events.commit.emit();
initialCommit = false;
},
nullptr, "CXDGSurfaceResource");
events.commit.emit();
initialCommit = false;
});
resource->setGetToplevel([this](CXdgSurface* r, uint32_t id) {
const auto RESOURCE = PROTO::xdgShell->m_vToplevels.emplace_back(makeShared<CXDGToplevelResource>(makeShared<CXdgToplevel>(r->client(), r->version(), id), self.lock()));
@ -649,7 +645,7 @@ CXDGWMBase::CXDGWMBase(SP<CXdgWmBase> resource_) : resource(resource_) {
resource->setGetXdgSurface([this](CXdgWmBase* r, uint32_t id, wl_resource* surf) {
const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back(
makeShared<CXDGSurfaceResource>(makeShared<CXdgSurface>(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surf)));
makeShared<CXDGSurfaceResource>(makeShared<CXdgSurface>(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surf)));
if (!RESOURCE->good()) {
r->noMemory();
@ -724,9 +720,9 @@ void CXDGShellProtocol::addOrStartGrab(SP<CXDGPopupResource> popup) {
grabOwner = popup;
grabbed.clear();
grab->clear();
grab->add(popup->surface->surface);
grab->add(popup->surface->surface.lock());
if (popup->parent)
grab->add(popup->parent->surface);
grab->add(popup->parent->surface.lock());
g_pSeatManager->setGrab(grab);
grabbed.emplace_back(popup);
return;
@ -734,10 +730,10 @@ void CXDGShellProtocol::addOrStartGrab(SP<CXDGPopupResource> popup) {
grabbed.emplace_back(popup);
grab->add(popup->surface->surface);
grab->add(popup->surface->surface.lock());
if (popup->parent)
grab->add(popup->parent->surface);
grab->add(popup->parent->surface.lock());
}
void CXDGShellProtocol::onPopupDestroy(WP<CXDGPopupResource> popup) {
@ -752,5 +748,5 @@ void CXDGShellProtocol::onPopupDestroy(WP<CXDGPopupResource> popup) {
std::erase(grabbed, popup);
if (popup->surface)
grab->remove(popup->surface->surface);
grab->remove(popup->surface->surface.lock());
}

View file

@ -16,6 +16,7 @@ class CXDGSurfaceResource;
class CXDGToplevelResource;
class CXDGPopupResource;
class CSeatGrab;
class CWLSurfaceResource;
struct SXDGPositionerState {
Vector2D requestedSize;
@ -138,7 +139,7 @@ class CXDGToplevelResource {
class CXDGSurfaceResource {
public:
CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, wlr_surface* surface_);
CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, SP<CWLSurfaceResource> surface_);
~CXDGSurfaceResource();
static SP<CXDGSurfaceResource> fromResource(wl_resource*);
@ -146,7 +147,7 @@ class CXDGSurfaceResource {
bool good();
WP<CXDGWMBase> owner;
wlr_surface* surface = nullptr;
WP<CWLSurfaceResource> surface;
WP<CXDGToplevelResource> toplevel;
WP<CXDGPopupResource> popup;
@ -184,8 +185,10 @@ class CXDGSurfaceResource {
//
std::vector<WP<CXDGPopupResource>> popups;
DYNLISTENER(surfaceDestroy);
DYNLISTENER(surfaceCommit);
struct {
CHyprSignalListener surfaceDestroy;
CHyprSignalListener surfaceCommit;
} listeners;
friend class CXDGPopupResource;
friend class CXDGToplevelResource;

View file

@ -1,9 +1,10 @@
#include "XWaylandShell.hpp"
#include "core/Compositor.hpp"
#include <algorithm>
#define LOGM PROTO::xwaylandShell->protoLog
CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, wlr_surface* surface_) : surface(surface_), resource(resource_) {
CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) {
if (!good())
return;
@ -45,7 +46,7 @@ CXWaylandShellResource::CXWaylandShellResource(SP<CXwaylandShellV1> resource_) :
resource->setGetXwaylandSurface([this](CXwaylandShellV1* r, uint32_t id, wl_resource* surface) {
const auto RESOURCE = PROTO::xwaylandShell->m_vSurfaces.emplace_back(
makeShared<CXWaylandSurfaceResource>(makeShared<CXwaylandSurfaceV1>(r->client(), r->version(), id), wlr_surface_from_resource(surface)));
makeShared<CXWaylandSurfaceResource>(makeShared<CXwaylandSurfaceV1>(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surface)));
if (!RESOURCE->good()) {
r->noMemory();

View file

@ -7,9 +7,11 @@
#include "xwayland-shell-v1.hpp"
#include "../helpers/signal/Signal.hpp"
class CWLSurfaceResource;
class CXWaylandSurfaceResource {
public:
CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, wlr_surface* surface_);
CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, SP<CWLSurfaceResource> surface_);
~CXWaylandSurfaceResource();
bool good();
@ -19,8 +21,8 @@ class CXWaylandSurfaceResource {
CSignal destroy;
} events;
uint64_t serial = 0;
wlr_surface* surface = nullptr;
uint64_t serial = 0;
WP<CWLSurfaceResource> surface;
WP<CXWaylandSurfaceResource> self;

View file

@ -0,0 +1,467 @@
#include "Compositor.hpp"
#include "Output.hpp"
#include "../types/WLBuffer.hpp"
#include <algorithm>
#include <ranges>
#include "Subcompositor.hpp"
#include "../Viewporter.hpp"
#include "../../helpers/Monitor.hpp"
#define LOGM PROTO::compositor->protoLog
class CDefaultSurfaceRole : public ISurfaceRole {
public:
virtual eSurfaceRole role() {
return SURFACE_ROLE_UNASSIGNED;
}
};
SP<CDefaultSurfaceRole> defaultRole = makeShared<CDefaultSurfaceRole>();
CWLCallbackResource::CWLCallbackResource(SP<CWlCallback> resource_) : resource(resource_) {
;
}
bool CWLCallbackResource::good() {
return resource->resource();
}
void CWLCallbackResource::send(timespec* now) {
resource->sendDone(now->tv_sec * 1000 + now->tv_nsec / 1000000);
}
CWLRegionResource::CWLRegionResource(SP<CWlRegion> resource_) : resource(resource_) {
if (!good())
return;
resource->setData(this);
resource->setDestroy([this](CWlRegion* r) { PROTO::compositor->destroyResource(this); });
resource->setOnDestroy([this](CWlRegion* r) { PROTO::compositor->destroyResource(this); });
resource->setAdd([this](CWlRegion* r, int32_t x, int32_t y, int32_t w, int32_t h) { region.add(CBox{x, y, w, h}); });
resource->setSubtract([this](CWlRegion* r, int32_t x, int32_t y, int32_t w, int32_t h) { region.subtract(CBox{x, y, w, h}); });
}
bool CWLRegionResource::good() {
return resource->resource();
}
SP<CWLRegionResource> CWLRegionResource::fromResource(wl_resource* res) {
auto data = (CWLRegionResource*)(((CWlRegion*)wl_resource_get_user_data(res))->data());
return data ? data->self.lock() : nullptr;
}
CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(resource_) {
if (!good())
return;
pClient = resource->client();
resource->setData(this);
role = defaultRole;
resource->setDestroy([this](CWlSurface* r) { destroy(); });
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) {
pending.offset = {x, y};
if (!buffer) {
pending.buffer.reset();
pending.texture.reset();
} else {
auto res = CWLBufferResource::fromResource(buffer);
pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr;
pending.size = res && res->buffer ? res->buffer->size : Vector2D{};
pending.texture = res && res->buffer ? res->buffer->texture : nullptr;
}
Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{};
Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{};
if (oldBufSize != newBufSize)
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
bufferReleased = false;
});
resource->setCommit([this](CWlSurface* r) {
if (pending.buffer)
pending.bufferDamage.intersect(CBox{{}, pending.buffer->size});
if (!pending.buffer)
pending.size = {};
else if (pending.viewport.hasDestination)
pending.size = pending.viewport.destination;
else if (pending.viewport.hasSource)
pending.size = pending.viewport.source.size();
else {
Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.buffer->size.y, pending.buffer->size.x} : pending.buffer->size;
pending.size = tfs / pending.scale;
}
if (viewportResource)
viewportResource->verify();
pending.damage.intersect(CBox{{}, pending.size});
CRegion previousBufferDamage = accumulateCurrentBufferDamage();
current = pending;
pending.damage.clear();
pending.bufferDamage.clear();
if (current.buffer && !bufferReleased) {
// without previous dolphin et al are weird vvv
//CRegion surfaceDamage =
// current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage);
current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this.
// release the buffer, glTexImage2D is synchronous (as in, data is consumed after the call returns)
// so we can let the app know we're done.
// for dma buffers, this doesn't matter.
current.buffer->sendRelease();
bufferReleased = true;
}
// TODO: we should _accumulate_ and not replace above if sync
if (role->role() == SURFACE_ROLE_SUBSURFACE) {
auto subsurface = (CWLSubsurfaceResource*)role.get();
if (subsurface->sync)
return;
events.commit.emit();
} else {
// send commit to all synced surfaces in this tree.
breadthfirst(
[](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) {
if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) {
auto subsurface = (CWLSubsurfaceResource*)surf->role.get();
if (!subsurface->sync)
return;
}
surf->events.commit.emit();
},
nullptr);
}
});
resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); });
resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.bufferDamage.add(CBox{x, y, w, h}); });
resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) { pending.scale = scale; });
resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) { pending.transform = (wl_output_transform)tr; });
resource->setSetInputRegion([this](CWlSurface* r, wl_resource* region) {
if (!region) {
pending.input = CBox{{}, {INT32_MAX, INT32_MAX}};
return;
}
auto RG = CWLRegionResource::fromResource(region);
pending.input = RG->region;
});
resource->setSetOpaqueRegion([this](CWlSurface* r, wl_resource* region) {
if (!region) {
pending.opaque = CBox{{}, {}};
return;
}
auto RG = CWLRegionResource::fromResource(region);
pending.opaque = RG->region;
});
resource->setFrame([this](CWlSurface* r, uint32_t id) { callbacks.emplace_back(makeShared<CWLCallbackResource>(makeShared<CWlCallback>(pClient, 1, id))); });
resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) { pending.offset = {x, y}; });
}
CWLSurfaceResource::~CWLSurfaceResource() {
events.destroy.emit();
}
void CWLSurfaceResource::destroy() {
if (mapped)
unmap();
events.destroy.emit();
PROTO::compositor->destroyResource(this);
}
SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) {
auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data());
return data ? data->self.lock() : nullptr;
}
bool CWLSurfaceResource::good() {
return resource->resource();
}
wl_client* CWLSurfaceResource::client() {
return pClient;
}
void CWLSurfaceResource::enter(SP<CMonitor> monitor) {
if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) != enteredOutputs.end())
return;
if (!PROTO::outputs.contains(monitor->szName)) {
// can happen on unplug/replug
LOGM(ERR, "enter() called on a non-existent output global");
return;
}
auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient);
if (!output || !output->getResource() || !output->getResource()->resource()) {
LOGM(ERR, "Cannot enter surface {:x} to {}, client hasn't bound the output", (uintptr_t)this, monitor->szName);
return;
}
enteredOutputs.emplace_back(monitor);
resource->sendEnter(output->getResource().get());
}
void CWLSurfaceResource::leave(SP<CMonitor> monitor) {
if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) == enteredOutputs.end())
return;
auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient);
if (!output) {
LOGM(ERR, "Cannot leave surface {:x} from {}, client hasn't bound the output", (uintptr_t)this, monitor->szName);
return;
}
std::erase(enteredOutputs, monitor);
resource->sendLeave(output->getResource().get());
}
void CWLSurfaceResource::sendPreferredTransform(wl_output_transform t) {
if (resource->version() < 6)
return;
resource->sendPreferredBufferTransform(t);
}
void CWLSurfaceResource::sendPreferredScale(int32_t scale) {
if (resource->version() < 6)
return;
resource->sendPreferredBufferScale(scale);
}
void CWLSurfaceResource::frame(timespec* now) {
if (callbacks.empty())
return;
for (auto& c : callbacks) {
c->send(now);
}
callbacks.clear();
}
void CWLSurfaceResource::resetRole() {
role = defaultRole;
}
void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
for (auto& n : nodes) {
Vector2D offset = {};
if (n->role->role() == SURFACE_ROLE_SUBSURFACE) {
auto subsurface = (CWLSubsurfaceResource*)n->role.get();
offset = subsurface->posRelativeToParent();
}
fn(n, offset, data);
}
std::vector<SP<CWLSurfaceResource>> nodes2;
for (auto& n : nodes) {
std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); });
for (auto& c : n->subsurfaces) {
nodes2.push_back(c->surface.lock());
}
}
if (!nodes2.empty())
bfHelper(nodes2, fn, data);
}
void CWLSurfaceResource::breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
std::vector<SP<CWLSurfaceResource>> surfs;
surfs.push_back(self.lock());
bfHelper(surfs, fn, data);
}
std::pair<SP<CWLSurfaceResource>, Vector2D> CWLSurfaceResource::at(const Vector2D& localCoords, bool allowsInput) {
std::vector<std::pair<SP<CWLSurfaceResource>, Vector2D>> surfs;
breadthfirst([](SP<CWLSurfaceResource> surf, const Vector2D& offset,
void* data) { ((std::vector<std::pair<SP<CWLSurfaceResource>, Vector2D>>*)data)->emplace_back(std::make_pair<>(surf, offset)); },
&surfs);
for (auto& [surf, pos] : surfs | std::views::reverse) {
if (!allowsInput) {
const auto BOX = CBox{pos, surf->current.size};
if (BOX.containsPoint(localCoords))
return {surf, localCoords - pos};
} else {
const auto REGION = surf->current.input.copy().intersect(CBox{{}, surf->current.size}).translate(pos);
if (REGION.containsPoint(localCoords))
return {surf, localCoords - pos};
}
}
return {nullptr, {}};
}
uint32_t CWLSurfaceResource::id() {
return wl_resource_get_id(resource->resource());
}
void CWLSurfaceResource::map() {
if (mapped)
return;
mapped = true;
events.map.emit();
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
frame(&now);
current.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
}
void CWLSurfaceResource::unmap() {
if (!mapped)
return;
mapped = false;
events.unmap.emit();
}
void CWLSurfaceResource::error(int code, const std::string& str) {
resource->error(code, str);
}
SP<CWlSurface> CWLSurfaceResource::getResource() {
return resource;
}
CBox CWLSurfaceResource::extends() {
CRegion full = CBox{{}, current.size};
breadthfirst(
[](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* d) {
if (surf->role->role() != SURFACE_ROLE_SUBSURFACE)
return;
((CRegion*)d)->add(CBox{offset, surf->current.size});
},
&full);
return full.getExtents();
}
Vector2D CWLSurfaceResource::sourceSize() {
if (!current.buffer)
return {};
if (current.viewport.hasSource)
return current.viewport.source.size();
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size;
return trc / current.scale;
}
CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
if (!current.buffer)
return {};
CRegion surfaceDamage = current.damage;
if (current.viewport.hasDestination) {
Vector2D scale = sourceSize() / current.viewport.destination;
surfaceDamage.scale(scale);
}
if (current.viewport.hasSource)
surfaceDamage.translate(current.viewport.source.pos());
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size;
return surfaceDamage.scale(current.scale).transform(wlr_output_transform_invert(current.transform), trc.x, trc.y).add(current.bufferDamage);
}
CWLCompositorResource::CWLCompositorResource(SP<CWlCompositor> resource_) : resource(resource_) {
if (!good())
return;
resource->setOnDestroy([this](CWlCompositor* r) { PROTO::compositor->destroyResource(this); });
resource->setCreateSurface([](CWlCompositor* r, uint32_t id) {
const auto RESOURCE = PROTO::compositor->m_vSurfaces.emplace_back(makeShared<CWLSurfaceResource>(makeShared<CWlSurface>(r->client(), r->version(), id)));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::compositor->m_vSurfaces.pop_back();
return;
}
RESOURCE->self = RESOURCE;
LOGM(LOG, "New wl_surface with id {} at {:x}", id, (uintptr_t)RESOURCE.get());
PROTO::compositor->events.newSurface.emit(RESOURCE);
});
resource->setCreateRegion([](CWlCompositor* r, uint32_t id) {
const auto RESOURCE = PROTO::compositor->m_vRegions.emplace_back(makeShared<CWLRegionResource>(makeShared<CWlRegion>(r->client(), r->version(), id)));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::compositor->m_vRegions.pop_back();
return;
}
RESOURCE->self = RESOURCE;
LOGM(LOG, "New wl_region with id {} at {:x}", id, (uintptr_t)RESOURCE.get());
});
}
bool CWLCompositorResource::good() {
return resource->resource();
}
CWLCompositorProtocol::CWLCompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CWLCompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CWLCompositorResource>(makeShared<CWlCompositor>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CWLCompositorProtocol::destroyResource(CWLCompositorResource* resource) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
}
void CWLCompositorProtocol::destroyResource(CWLSurfaceResource* resource) {
std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; });
}
void CWLCompositorProtocol::destroyResource(CWLRegionResource* resource) {
std::erase_if(m_vRegions, [&](const auto& other) { return other.get() == resource; });
}

View file

@ -0,0 +1,175 @@
#pragma once
/*
Implementations for:
- wl_compositor
- wl_surface
- wl_region
- wl_callback
*/
#include <memory>
#include <vector>
#include <cstdint>
#include "../WaylandProtocol.hpp"
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../helpers/Region.hpp"
#include "../types/Buffer.hpp"
#include "../types/SurfaceRole.hpp"
class CWLOutputResource;
class CMonitor;
class CWLSurface;
class CWLSurfaceResource;
class CWLSubsurfaceResource;
class CViewportResource;
class CWLCallbackResource {
public:
CWLCallbackResource(SP<CWlCallback> resource_);
bool good();
void send(timespec* now);
private:
SP<CWlCallback> resource;
};
class CWLRegionResource {
public:
CWLRegionResource(SP<CWlRegion> resource_);
static SP<CWLRegionResource> fromResource(wl_resource* res);
bool good();
CRegion region;
WP<CWLRegionResource> self;
private:
SP<CWlRegion> resource;
};
class CWLSurfaceResource {
public:
CWLSurfaceResource(SP<CWlSurface> resource_);
~CWLSurfaceResource();
static SP<CWLSurfaceResource> fromResource(wl_resource* res);
bool good();
wl_client* client();
void enter(SP<CMonitor> monitor);
void leave(SP<CMonitor> monitor);
void sendPreferredTransform(wl_output_transform t);
void sendPreferredScale(int32_t scale);
void frame(timespec* now);
uint32_t id();
void map();
void unmap();
void error(int code, const std::string& str);
SP<CWlSurface> getResource();
CBox extends();
void resetRole();
Vector2D sourceSize();
struct {
CSignal commit;
CSignal map;
CSignal unmap;
CSignal newSubsurface;
CSignal destroy;
} events;
struct {
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
int scale = 1;
SP<IWLBuffer> buffer;
SP<CTexture> texture;
Vector2D offset;
Vector2D size;
struct {
bool hasDestination = false;
bool hasSource = false;
Vector2D destination;
CBox source;
} viewport;
//
void reset() {
damage.clear();
bufferDamage.clear();
transform = WL_OUTPUT_TRANSFORM_NORMAL;
scale = 1;
offset = {};
size = {};
}
} current, pending;
std::vector<SP<CWLCallbackResource>> callbacks;
WP<CWLSurfaceResource> self;
WP<CWLSurface> hlSurface;
std::vector<WP<CMonitor>> enteredOutputs;
bool mapped = false;
std::vector<WP<CWLSubsurfaceResource>> subsurfaces;
WP<ISurfaceRole> role;
WP<CViewportResource> viewportResource;
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
CRegion accumulateCurrentBufferDamage();
// returns a pair: found surface (null if not found) and surface local coords.
// localCoords param is relative to 0,0 of this surface
std::pair<SP<CWLSurfaceResource>, Vector2D> at(const Vector2D& localCoords, bool allowsInput = false);
private:
SP<CWlSurface> resource;
wl_client* pClient = nullptr;
// tracks whether we should release the buffer
bool bufferReleased = false;
void destroy();
void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
};
class CWLCompositorResource {
public:
CWLCompositorResource(SP<CWlCompositor> resource_);
bool good();
private:
SP<CWlCompositor> resource;
};
class CWLCompositorProtocol : public IWaylandProtocol {
public:
CWLCompositorProtocol(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);
struct {
CSignal newSurface; // SP<CWLSurfaceResource>
} events;
private:
void destroyResource(CWLCompositorResource* resource);
void destroyResource(CWLSurfaceResource* resource);
void destroyResource(CWLRegionResource* resource);
//
std::vector<SP<CWLCompositorResource>> m_vManagers;
std::vector<SP<CWLSurfaceResource>> m_vSurfaces;
std::vector<SP<CWLRegionResource>> m_vRegions;
friend class CWLSurfaceResource;
friend class CWLCompositorResource;
friend class CWLRegionResource;
friend class CWLCallbackResource;
};
namespace PROTO {
inline UP<CWLCompositorProtocol> compositor;
};

View file

@ -4,6 +4,7 @@
#include "../../managers/PointerManager.hpp"
#include "../../Compositor.hpp"
#include "Seat.hpp"
#include "Compositor.hpp"
#define LOGM PROTO::data->protoLog
@ -233,7 +234,7 @@ CWLDataDeviceResource::CWLDataDeviceResource(SP<CWlDataDevice> resource_) : reso
source->dnd = true;
PROTO::data->initiateDrag(source, icon ? wlr_surface_from_resource(icon) : nullptr, wlr_surface_from_resource(origin));
PROTO::data->initiateDrag(source, icon ? CWLSurfaceResource::fromResource(icon) : nullptr, CWLSurfaceResource::fromResource(origin));
});
}
@ -252,8 +253,8 @@ void CWLDataDeviceResource::sendDataOffer(SP<CWLDataOfferResource> offer) {
resource->sendDataOfferRaw(nullptr);
}
void CWLDataDeviceResource::sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP<CWLDataOfferResource> offer) {
resource->sendEnterRaw(serial, surf->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource());
void CWLDataDeviceResource::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<CWLDataOfferResource> offer) {
resource->sendEnterRaw(serial, surf->getResource()->resource(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource());
}
void CWLDataDeviceResource::sendLeave() {
@ -454,7 +455,7 @@ void CWLDataDeviceProtocol::onKeyboardFocus() {
updateDrag();
}
void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource, wlr_surface* dragSurface, wlr_surface* origin) {
void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource, SP<CWLSurfaceResource> dragSurface, SP<CWLSurfaceResource> origin) {
if (dnd.currentSource) {
LOGM(WARN, "New drag started while old drag still active??");
@ -472,22 +473,18 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
dnd.originSurface = origin;
dnd.dndSurface = dragSurface;
if (dragSurface) {
dnd.hyprListener_dndSurfaceDestroy.initCallback(
&dragSurface->events.destroy, [this](void* owner, void* data) { abortDrag(); }, nullptr, "CWLDataDeviceProtocol::drag");
dnd.hyprListener_dndSurfaceCommit.initCallback(
&dragSurface->events.commit,
[this](void* owner, void* data) {
if (dnd.dndSurface->pending.buffer_width > 0 && dnd.dndSurface->pending.buffer_height > 0 && !dnd.dndSurface->mapped) {
wlr_surface_map(dnd.dndSurface);
return;
}
dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); });
dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) {
if (dnd.dndSurface->current.buffer && !dnd.dndSurface->mapped) {
dnd.dndSurface->map();
return;
}
if (dnd.dndSurface->pending.buffer_width <= 0 && dnd.dndSurface->pending.buffer_height <= 0 && dnd.dndSurface->mapped) {
wlr_surface_unmap(dnd.dndSurface);
return;
}
},
nullptr, "CWLDataDeviceProtocol::drag");
if (dnd.dndSurface->current.buffer <= 0 && dnd.dndSurface->mapped) {
dnd.dndSurface->unmap();
return;
}
});
}
dnd.mouseButton = g_pHookSystem->hookDynamic("mouseButton", [this](void* self, SCallbackInfo& info, std::any e) {
@ -506,7 +503,7 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
dnd.mouseMove = g_pHookSystem->hookDynamic("mouseMove", [this](void* self, SCallbackInfo& info, std::any e) {
auto V = std::any_cast<const Vector2D>(e);
if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) {
auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus);
auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock());
if (!surf)
return;
@ -524,7 +521,7 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
dnd.touchMove = g_pHookSystem->hookDynamic("touchMove", [this](void* self, SCallbackInfo& info, std::any e) {
auto E = std::any_cast<ITouch::SMotionEvent>(e);
if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) {
auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus);
auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock());
if (!surf)
return;
@ -572,14 +569,14 @@ void CWLDataDeviceProtocol::updateDrag() {
dnd.focusedDevice->sendDataOffer(OFFER);
OFFER->sendData();
dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus,
Vector2D{g_pSeatManager->state.keyboardFocus->current.width, g_pSeatManager->state.keyboardFocus->current.height} / 2.F, OFFER);
dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus.lock(),
g_pSeatManager->state.keyboardFocus->current.size / 2.F, OFFER);
}
void CWLDataDeviceProtocol::resetDndState() {
dnd.dndSurface = nullptr;
dnd.hyprListener_dndSurfaceDestroy.removeCallback();
dnd.hyprListener_dndSurfaceCommit.removeCallback();
dnd.dndSurface.reset();
dnd.dndSurfaceCommit.reset();
dnd.dndSurfaceDestroy.reset();
dnd.mouseButton.reset();
dnd.mouseMove.reset();
dnd.touchUp.reset();
@ -638,20 +635,18 @@ void CWLDataDeviceProtocol::abortDrag() {
}
void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
if (!dnd.dndSurface || !wlr_surface_get_texture(dnd.dndSurface))
if (!dnd.dndSurface || !dnd.dndSurface->current.buffer || !dnd.dndSurface->current.buffer->texture)
return;
const auto POS = g_pInputManager->getMouseCoordsInternal();
CBox box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}}
.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F)
.scale(pMonitor->scale);
g_pHyprOpenGL->renderTexture(wlr_surface_get_texture(dnd.dndSurface), &box, 1.F);
CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale);
g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.buffer->texture, &box, 1.F);
box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}}.translate(g_pPointerManager->cursorSizeLogical() / 2.F);
box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F);
g_pHyprRenderer->damageBox(&box);
wlr_surface_send_frame_done(dnd.dndSurface, when);
dnd.dndSurface->frame(when);
}
bool CWLDataDeviceProtocol::dndActive() {

View file

@ -23,6 +23,7 @@ class CWLDataDeviceManagerResource;
class CWLDataSourceResource;
class CWLDataOfferResource;
class CWLSurfaceResource;
class CMonitor;
class CWLDataOfferResource {
@ -92,7 +93,7 @@ class CWLDataDeviceResource {
wl_client* client();
void sendDataOffer(SP<CWLDataOfferResource> offer);
void sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP<CWLDataOfferResource> offer);
void sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<CWLDataOfferResource> offer);
void sendLeave();
void sendMotion(uint32_t timeMs, const Vector2D& local);
void sendDrop();
@ -155,11 +156,11 @@ class CWLDataDeviceProtocol : public IWaylandProtocol {
struct {
WP<CWLDataDeviceResource> focusedDevice;
WP<CWLDataSourceResource> currentSource;
wlr_surface* dndSurface = nullptr;
wlr_surface* originSurface = nullptr; // READ-ONLY
WP<CWLSurfaceResource> dndSurface;
WP<CWLSurfaceResource> originSurface;
bool overriddenCursor = false;
DYNLISTENER(dndSurfaceDestroy);
DYNLISTENER(dndSurfaceCommit);
CHyprSignalListener dndSurfaceDestroy;
CHyprSignalListener dndSurfaceCommit;
// for ending a dnd
SP<HOOK_CALLBACK_FN> mouseMove;
@ -169,7 +170,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol {
} dnd;
void abortDrag();
void initiateDrag(WP<CWLDataSourceResource> currentSource, wlr_surface* dragSurface, wlr_surface* origin);
void initiateDrag(WP<CWLDataSourceResource> currentSource, SP<CWLSurfaceResource> dragSurface, SP<CWLSurfaceResource> origin);
void updateDrag();
void dropDrag();
void completeDrag();

View file

@ -0,0 +1,107 @@
#include "Output.hpp"
#include "../../helpers/Monitor.hpp"
CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMonitor) : monitor(pMonitor), resource(resource_) {
if (!good())
return;
resource->setData(this);
pClient = resource->client();
resource->setOnDestroy([this](CWlOutput* r) {
if (monitor && PROTO::outputs.contains(monitor->szName))
PROTO::outputs.at(monitor->szName)->destroyResource(this);
});
resource->setRelease([this](CWlOutput* r) {
if (monitor && PROTO::outputs.contains(monitor->szName))
PROTO::outputs.at(monitor->szName)->destroyResource(this);
});
resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null",
monitor->output->model ? monitor->output->model : "null", monitor->transform);
if (resource->version() >= 4) {
resource->sendName(monitor->szName.c_str());
resource->sendDescription(monitor->szDescription.c_str());
}
updateState();
}
SP<CWLOutputResource> CWLOutputResource::fromResource(wl_resource* res) {
auto data = (CWLOutputResource*)(((CWlOutput*)wl_resource_get_user_data(res))->data());
return data ? data->self.lock() : nullptr;
}
bool CWLOutputResource::good() {
return resource->resource();
}
wl_client* CWLOutputResource::client() {
return pClient;
}
SP<CWlOutput> CWLOutputResource::getResource() {
return resource;
}
void CWLOutputResource::updateState() {
if (!monitor)
return;
if (resource->version() >= 2)
resource->sendScale(std::ceil(monitor->scale));
resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED), monitor->vecSize.x, monitor->vecSize.y, monitor->refreshRate * 1000.0);
if (resource->version() >= 2)
resource->sendDone();
}
CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP<CMonitor> pMonitor) :
IWaylandProtocol(iface, ver, name), monitor(pMonitor), szName(pMonitor->szName) {
listeners.modeChanged = monitor->events.modeChanged.registerListener([this](std::any d) {
for (auto& o : m_vOutputs) {
o->updateState();
}
});
}
void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vOutputs.emplace_back(makeShared<CWLOutputResource>(makeShared<CWlOutput>(client, ver, id), monitor.lock()));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vOutputs.pop_back();
return;
}
RESOURCE->self = RESOURCE;
}
void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) {
std::erase_if(m_vOutputs, [&](const auto& other) { return other.get() == resource; });
if (m_vOutputs.empty() && defunct)
PROTO::outputs.erase(szName);
}
SP<CWLOutputResource> CWLOutputProtocol::outputResourceFrom(wl_client* client) {
for (auto& r : m_vOutputs) {
if (r->client() != client)
continue;
return r;
}
return nullptr;
}
void CWLOutputProtocol::remove() {
if (defunct)
return;
defunct = true;
removeGlobal();
}

View file

@ -0,0 +1,61 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "../WaylandProtocol.hpp"
#include "wayland.hpp"
#include "../../helpers/signal/Listener.hpp"
class CMonitor;
class CWLOutputResource {
public:
CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMonitor);
static SP<CWLOutputResource> fromResource(wl_resource*);
bool good();
wl_client* client();
SP<CWlOutput> getResource();
void updateState();
WP<CMonitor> monitor;
WP<CWLOutputResource> self;
private:
SP<CWlOutput> resource;
wl_client* pClient = nullptr;
};
class CWLOutputProtocol : public IWaylandProtocol {
public:
CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP<CMonitor> pMonitor);
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
SP<CWLOutputResource> outputResourceFrom(wl_client* client);
WP<CMonitor> monitor;
// will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global)
void remove();
private:
void destroyResource(CWLOutputResource* resource);
//
std::vector<SP<CWLOutputResource>> m_vOutputs;
bool defunct = false;
std::string szName = "";
struct {
CHyprSignalListener modeChanged;
} listeners;
friend class CWLOutputResource;
};
namespace PROTO {
inline std::unordered_map<std::string, UP<CWLOutputProtocol>> outputs;
};

View file

@ -1,4 +1,5 @@
#include "Seat.hpp"
#include "Compositor.hpp"
#include "../../devices/IKeyboard.hpp"
#include "../../managers/SeatManager.hpp"
#include "../../config/ConfigValue.hpp"
@ -20,7 +21,7 @@ bool CWLTouchResource::good() {
return resource->resource();
}
void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local) {
void CWLTouchResource::sendDown(SP<CWLSurfaceResource> surface, uint32_t timeMs, int32_t id, const Vector2D& local) {
if (!owner)
return;
@ -29,15 +30,12 @@ void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t i
sendUp(timeMs, id);
}
ASSERT(wl_resource_get_client(surface->resource) == owner->client());
ASSERT(surface->client() == owner->client());
currentSurface = surface;
hyprListener_surfaceDestroy.initCallback(
&surface->events.destroy, [this, id, timeMs](void* owner, void* data) { sendUp(timeMs + 10 /* hack */, id); }, this, "CWLTouchResource");
currentSurface = surface;
listeners.destroySurface = surface->events.destroy.registerListener([this, timeMs, id](std::any d) { sendUp(timeMs + 10 /* hack */, id); });
// FIXME:
// fix this once we get our own wlr_surface, this is horrible
resource->sendDownRaw(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->resource, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
resource->sendDown(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->getResource().get(), id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
}
void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) {
@ -45,8 +43,8 @@ void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) {
return;
resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id);
currentSurface = nullptr;
hyprListener_surfaceDestroy.removeCallback();
currentSurface.reset();
listeners.destroySurface.reset();
}
void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) {
@ -97,7 +95,7 @@ CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResou
return;
}
g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? wlr_surface_from_resource(surf) : nullptr, {hotX, hotY});
g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY});
});
}
@ -105,7 +103,7 @@ bool CWLPointerResource::good() {
return resource->resource();
}
void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local) {
void CWLPointerResource::sendEnter(SP<CWLSurfaceResource> surface, const Vector2D& local) {
if (!owner || currentSurface == surface)
return;
@ -114,22 +112,21 @@ void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local)
sendLeave();
}
ASSERT(wl_resource_get_client(surface->resource) == owner->client());
ASSERT(surface->client() == owner->client());
currentSurface = surface;
hyprListener_surfaceDestroy.initCallback(
&surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLPointerResource");
currentSurface = surface;
listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); });
resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
}
void CWLPointerResource::sendLeave() {
if (!owner || !currentSurface)
return;
resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource);
currentSurface = nullptr;
hyprListener_surfaceDestroy.removeCallback();
resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get());
currentSurface.reset();
listeners.destroySurface.reset();
}
void CWLPointerResource::sendMotion(uint32_t timeMs, const Vector2D& local) {
@ -237,7 +234,7 @@ void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) {
close(fd);
}
void CWLKeyboardResource::sendEnter(wlr_surface* surface) {
void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface) {
if (!owner || currentSurface == surface)
return;
@ -246,16 +243,15 @@ void CWLKeyboardResource::sendEnter(wlr_surface* surface) {
sendLeave();
}
ASSERT(wl_resource_get_client(surface->resource) == owner->client());
ASSERT(surface->client() == owner->client());
currentSurface = surface;
hyprListener_surfaceDestroy.initCallback(
&surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLKeyboardResource");
currentSurface = surface;
listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); });
wl_array arr;
wl_array_init(&arr);
resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, &arr);
resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), &arr);
wl_array_release(&arr);
}
@ -264,9 +260,9 @@ void CWLKeyboardResource::sendLeave() {
if (!owner || !currentSurface)
return;
resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource);
currentSurface = nullptr;
hyprListener_surfaceDestroy.removeCallback();
resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get());
currentSurface.reset();
listeners.destroySurface.reset();
}
void CWLKeyboardResource::sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) {

View file

@ -20,6 +20,7 @@
constexpr const char* HL_SEAT_NAME = "Hyprland";
class IKeyboard;
class CWLSurfaceResource;
class CWLPointerResource;
class CWLKeyboardResource;
@ -31,7 +32,7 @@ class CWLTouchResource {
CWLTouchResource(SP<CWlTouch> resource_, SP<CWLSeatResource> owner_);
bool good();
void sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local);
void sendDown(SP<CWLSurfaceResource> surface, uint32_t timeMs, int32_t id, const Vector2D& local);
void sendUp(uint32_t timeMs, int32_t id);
void sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local);
void sendFrame();
@ -42,10 +43,12 @@ class CWLTouchResource {
WP<CWLSeatResource> owner;
private:
SP<CWlTouch> resource;
wlr_surface* currentSurface = nullptr;
SP<CWlTouch> resource;
WP<CWLSurfaceResource> currentSurface;
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroySurface;
} listeners;
};
class CWLPointerResource {
@ -53,7 +56,7 @@ class CWLPointerResource {
CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResource> owner_);
bool good();
void sendEnter(wlr_surface* surface, const Vector2D& local);
void sendEnter(SP<CWLSurfaceResource> surface, const Vector2D& local);
void sendLeave();
void sendMotion(uint32_t timeMs, const Vector2D& local);
void sendButton(uint32_t timeMs, uint32_t button, wl_pointer_button_state state);
@ -68,10 +71,12 @@ class CWLPointerResource {
WP<CWLSeatResource> owner;
private:
SP<CWlPointer> resource;
wlr_surface* currentSurface = nullptr;
SP<CWlPointer> resource;
WP<CWLSurfaceResource> currentSurface;
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroySurface;
} listeners;
};
class CWLKeyboardResource {
@ -80,7 +85,7 @@ class CWLKeyboardResource {
bool good();
void sendKeymap(SP<IKeyboard> keeb);
void sendEnter(wlr_surface* surface);
void sendEnter(SP<CWLSurfaceResource> surface);
void sendLeave();
void sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state);
void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
@ -89,10 +94,12 @@ class CWLKeyboardResource {
WP<CWLSeatResource> owner;
private:
SP<CWlKeyboard> resource;
wlr_surface* currentSurface = nullptr;
SP<CWlKeyboard> resource;
WP<CWLSurfaceResource> currentSurface;
DYNLISTENER(surfaceDestroy);
struct {
CHyprSignalListener destroySurface;
} listeners;
};
class CWLSeatResource {

214
src/protocols/core/Shm.cpp Normal file
View file

@ -0,0 +1,214 @@
#include "Shm.hpp"
#include <algorithm>
#include <sys/mman.h>
#include <drm_fourcc.h>
#include "../../render/Texture.hpp"
#include "../types/WLBuffer.hpp"
#include "../../Compositor.hpp"
#include "../../helpers/Format.hpp"
#define LOGM PROTO::shm->protoLog
CWLSHMBuffer::CWLSHMBuffer(SP<CWLSHMPoolResource> pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) {
if (!pool_->pool->data)
return;
g_pHyprRenderer->makeEGLCurrent();
size = size_;
pool = pool_->pool;
stride = stride_;
fmt = fmt_;
offset = offset_;
opaque = FormatUtils::isFormatOpaque(FormatUtils::shmToDRM(fmt_));
texture = makeShared<CTexture>(FormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, size_);
resource = CWLBufferResource::create(makeShared<CWlBuffer>(pool_->resource->client(), 1, id));
listeners.bufferResourceDestroy = events.destroy.registerListener([this](std::any d) {
listeners.bufferResourceDestroy.reset();
PROTO::shm->destroyResource(this);
});
success = texture->m_iTexID;
if (!success)
Debug::log(ERR, "Failed creating a shm texture: null texture id");
}
CWLSHMBuffer::~CWLSHMBuffer() {
;
}
eBufferCapability CWLSHMBuffer::caps() {
return BUFFER_CAPABILITY_DATAPTR;
}
eBufferType CWLSHMBuffer::type() {
return BUFFER_TYPE_SHM;
}
SSHMAttrs CWLSHMBuffer::shm() {
SSHMAttrs attrs;
attrs.success = true;
attrs.fd = pool->fd;
attrs.format = FormatUtils::shmToDRM(fmt);
attrs.size = size;
attrs.stride = stride;
attrs.offset = offset;
return attrs;
}
std::tuple<uint8_t*, uint32_t, size_t> CWLSHMBuffer::beginDataPtr(uint32_t flags) {
return {(uint8_t*)pool->data + offset, fmt, size.x * size.y * 4};
}
void CWLSHMBuffer::endDataPtr() {
;
}
bool CWLSHMBuffer::good() {
return success;
}
void CWLSHMBuffer::update(const CRegion& damage) {
texture->update(FormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage);
}
CSHMPool::CSHMPool(int fd_, size_t size_) : fd(fd_), size(size_) {
data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
}
CSHMPool::~CSHMPool() {
munmap(data, size);
close(fd);
}
void CSHMPool::resize(size_t size_) {
LOGM(LOG, "Resizing a SHM pool from {} to {}", size, size_);
if (data)
munmap(data, size);
size = size_;
data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (!data)
LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd);
}
CWLSHMPoolResource::CWLSHMPoolResource(SP<CWlShmPool> resource_, int fd_, size_t size_) : resource(resource_) {
if (!good())
return;
pool = makeShared<CSHMPool>(fd_, size_);
resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); });
resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); });
resource->setResize([this](CWlShmPool* r, int32_t size_) {
if (size_ < (int32_t)pool->size) {
r->error(-1, "Shrinking a shm pool is illegal");
return;
}
pool->resize(size_);
});
resource->setCreateBuffer([this](CWlShmPool* r, uint32_t id, int32_t offset, int32_t w, int32_t h, int32_t stride, uint32_t fmt) {
if (!pool || !pool->data) {
r->error(-1, "The provided shm pool failed to allocate properly");
return;
}
if (std::find(PROTO::shm->shmFormats.begin(), PROTO::shm->shmFormats.end(), fmt) == PROTO::shm->shmFormats.end()) {
r->error(WL_SHM_ERROR_INVALID_FORMAT, "Format invalid");
return;
}
if (offset < 0 || w <= 0 || h <= 0 || stride <= 0) {
r->error(WL_SHM_ERROR_INVALID_STRIDE, "Invalid stride, w, h, or offset");
return;
}
const auto RESOURCE = PROTO::shm->m_vBuffers.emplace_back(makeShared<CWLSHMBuffer>(self.lock(), id, offset, Vector2D{w, h}, stride, fmt));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::shm->m_vBuffers.pop_back();
return;
}
// append instance so that buffer knows its owner
RESOURCE->resource->buffer = RESOURCE;
});
if (!pool->data)
resource->error(WL_SHM_ERROR_INVALID_FD, "Couldn't mmap from fd");
}
bool CWLSHMPoolResource::good() {
return resource->resource();
}
CWLSHMResource::CWLSHMResource(SP<CWlShm> resource_) : resource(resource_) {
if (!good())
return;
resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); });
resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) {
const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared<CWLSHMPoolResource>(makeShared<CWlShmPool>(r->client(), r->version(), id), fd, size));
if (!RESOURCE->good()) {
r->noMemory();
PROTO::shm->m_vPools.pop_back();
return;
}
RESOURCE->self = RESOURCE;
});
// send a few supported formats. No need for any other I think?
for (auto& s : PROTO::shm->shmFormats) {
resource->sendFormat((wl_shm_format)s);
}
}
bool CWLSHMResource::good() {
return resource->resource();
}
CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
if (shmFormats.empty()) {
size_t len = 0;
const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len);
for (size_t i = 0; i < len; ++i) {
shmFormats.push_back(FormatUtils::drmToShm(formats[i]));
}
}
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CWLSHMResource>(makeShared<CWlShm>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CWLSHMProtocol::destroyResource(CWLSHMResource* resource) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
}
void CWLSHMProtocol::destroyResource(CWLSHMPoolResource* resource) {
std::erase_if(m_vPools, [&](const auto& other) { return other.get() == resource; });
}
void CWLSHMProtocol::destroyResource(CWLSHMBuffer* resource) {
std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; });
}

111
src/protocols/core/Shm.hpp Normal file
View file

@ -0,0 +1,111 @@
#pragma once
/*
Implementations for:
- wl_shm
- wl_shm_pool
- wl_buffer with shm
*/
#include <memory>
#include <vector>
#include <cstdint>
#include "../WaylandProtocol.hpp"
#include "wayland.hpp"
#include "../types/Buffer.hpp"
#include "../../helpers/Vector2D.hpp"
class CWLSHMPoolResource;
class CSHMPool {
public:
CSHMPool(int fd, size_t size);
~CSHMPool();
int fd = 0;
size_t size = 0;
void* data = nullptr;
void resize(size_t size);
};
class CWLSHMBuffer : public IWLBuffer {
public:
CWLSHMBuffer(SP<CWLSHMPoolResource> pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt);
virtual ~CWLSHMBuffer();
virtual eBufferCapability caps();
virtual eBufferType type();
virtual void update(const CRegion& damage);
virtual SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
bool good();
void updateTexture();
int32_t offset = 0, stride = 0;
uint32_t fmt = 0;
SP<CSHMPool> pool;
private:
bool success = false;
struct {
CHyprSignalListener bufferResourceDestroy;
} listeners;
};
class CWLSHMPoolResource {
public:
CWLSHMPoolResource(SP<CWlShmPool> resource_, int fd, size_t size);
bool good();
SP<CSHMPool> pool;
WP<CWLSHMPoolResource> self;
private:
SP<CWlShmPool> resource;
friend class CWLSHMBuffer;
};
class CWLSHMResource {
public:
CWLSHMResource(SP<CWlShm> resource_);
bool good();
private:
SP<CWlShm> resource;
};
class CWLSHMProtocol : public IWaylandProtocol {
public:
CWLSHMProtocol(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 destroyResource(CWLSHMResource* resource);
void destroyResource(CWLSHMPoolResource* resource);
void destroyResource(CWLSHMBuffer* resource);
//
std::vector<SP<CWLSHMResource>> m_vManagers;
std::vector<SP<CWLSHMPoolResource>> m_vPools;
std::vector<SP<CWLSHMBuffer>> m_vBuffers;
//
std::vector<uint32_t> shmFormats;
friend class CWLSHMResource;
friend class CWLSHMPoolResource;
friend class CWLSHMBuffer;
};
namespace PROTO {
inline UP<CWLSHMProtocol> shm;
};

View file

@ -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; });
}

View file

@ -0,0 +1,82 @@
#pragma once
/*
Implementations for:
- wl_subsurface
- wl_subcompositor
*/
#include <memory>
#include <vector>
#include <cstdint>
#include "../WaylandProtocol.hpp"
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../types/SurfaceRole.hpp"
class CWLSurfaceResource;
class CWLSubsurfaceResource : public ISurfaceRole {
public:
CWLSubsurfaceResource(SP<CWlSubsurface> resource_, SP<CWLSurfaceResource> surface_, SP<CWLSurfaceResource> parent_);
~CWLSubsurfaceResource();
Vector2D posRelativeToParent();
bool good();
virtual eSurfaceRole role();
SP<CWLSurfaceResource> t1Parent();
bool sync = false;
Vector2D position;
WP<CWLSurfaceResource> surface;
WP<CWLSurfaceResource> parent;
WP<CWLSubsurfaceResource> self;
struct {
CSignal destroy;
} events;
private:
SP<CWlSubsurface> resource;
void destroy();
struct {
CHyprSignalListener commitSurface;
} listeners;
};
class CWLSubcompositorResource {
public:
CWLSubcompositorResource(SP<CWlSubcompositor> resource_);
bool good();
private:
SP<CWlSubcompositor> resource;
};
class CWLSubcompositorProtocol : public IWaylandProtocol {
public:
CWLSubcompositorProtocol(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 destroyResource(CWLSubcompositorResource* resource);
void destroyResource(CWLSubsurfaceResource* resource);
//
std::vector<SP<CWLSubcompositorResource>> m_vManagers;
std::vector<SP<CWLSubsurfaceResource>> m_vSurfaces;
friend class CWLSubcompositorResource;
friend class CWLSubsurfaceResource;
};
namespace PROTO {
inline UP<CWLSubcompositorProtocol> subcompositor;
};

View file

@ -0,0 +1,41 @@
#include "Buffer.hpp"
#include "WLBuffer.hpp"
SDMABUFAttrs IWLBuffer::dmabuf() {
return SDMABUFAttrs{};
}
SSHMAttrs IWLBuffer::shm() {
return SSHMAttrs{};
}
std::tuple<uint8_t*, uint32_t, size_t> IWLBuffer::beginDataPtr(uint32_t flags) {
return {nullptr, 0, 0};
}
void IWLBuffer::endDataPtr() {
; // empty
}
void IWLBuffer::sendRelease() {
if (!resource || !resource->resource)
return;
resource->resource->sendRelease();
}
void IWLBuffer::lock() {
locks++;
}
void IWLBuffer::unlock() {
locks--;
ASSERT(locks >= 0);
if (locks <= 0)
sendRelease();
}
bool IWLBuffer::locked() {
return locks;
}

View file

@ -0,0 +1,74 @@
#pragma once
#include "../../defines.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../render/Texture.hpp"
#include <array>
#include <tuple>
enum eBufferCapability {
BUFFER_CAPABILITY_DATAPTR = (1 << 0),
};
enum eBufferType {
BUFFER_TYPE_DMABUF = 0,
BUFFER_TYPE_SHM,
BUFFER_TYPE_MISC,
};
class CWLBufferResource;
struct SDMABUFAttrs {
bool success = false;
Vector2D size;
uint32_t format = 0; // fourcc
uint64_t modifier = 0;
int planes = 1;
std::array<uint32_t, 4> offsets = {0};
std::array<uint32_t, 4> strides = {0};
std::array<int, 4> fds = {-1, -1, -1, -1};
};
struct SSHMAttrs {
bool success = false;
int fd = 0;
uint32_t format = 0;
Vector2D size;
int stride = 0;
int64_t offset = 0;
};
class IWLBuffer {
public:
virtual ~IWLBuffer() {
;
};
virtual eBufferCapability caps() = 0;
virtual eBufferType type() = 0;
virtual void update(const CRegion& damage) = 0;
virtual SDMABUFAttrs dmabuf();
virtual SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
virtual void sendRelease();
virtual void lock();
virtual void unlock();
virtual bool locked();
Vector2D size;
bool opaque = false;
SP<CWLBufferResource> resource;
SP<CTexture> texture;
struct {
CSignal destroy;
} events;
private:
int locks = 0;
};

View file

@ -0,0 +1,75 @@
#include "DMABuffer.hpp"
#include "WLBuffer.hpp"
#include "../../render/Renderer.hpp"
#include "../../helpers/Format.hpp"
CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) : attrs(attrs_) {
g_pHyprRenderer->makeEGLCurrent();
listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) {
closeFDs();
listeners.resourceDestroy.reset();
});
size = attrs.size;
resource = CWLBufferResource::create(makeShared<CWlBuffer>(client, 1, id));
auto eglImage = g_pHyprOpenGL->createEGLImage(attrs);
if (!eglImage)
return;
texture = makeShared<CTexture>(attrs, eglImage); // texture takes ownership of the eglImage
opaque = FormatUtils::isFormatOpaque(attrs.format);
success = texture->m_iTexID;
if (!success)
Debug::log(ERR, "Failed to create a dmabuf: texture is null");
}
CDMABuffer::~CDMABuffer() {
closeFDs();
}
eBufferCapability CDMABuffer::caps() {
return BUFFER_CAPABILITY_DATAPTR;
}
eBufferType CDMABuffer::type() {
return BUFFER_TYPE_DMABUF;
}
void CDMABuffer::update(const CRegion& damage) {
;
}
SDMABUFAttrs CDMABuffer::dmabuf() {
return attrs;
}
std::tuple<uint8_t*, uint32_t, size_t> CDMABuffer::beginDataPtr(uint32_t flags) {
// FIXME:
return {nullptr, 0, 0};
}
void CDMABuffer::endDataPtr() {
// FIXME:
}
bool CDMABuffer::good() {
return success;
}
void CDMABuffer::updateTexture() {
;
}
void CDMABuffer::closeFDs() {
for (int i = 0; i < attrs.planes; ++i) {
if (attrs.fds[i] == -1)
continue;
close(attrs.fds[i]);
attrs.fds[i] = -1;
}
attrs.planes = 0;
}

View file

@ -0,0 +1,28 @@
#pragma once
#include "Buffer.hpp"
class CDMABuffer : public IWLBuffer {
public:
CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_);
virtual ~CDMABuffer();
virtual eBufferCapability caps();
virtual eBufferType type();
virtual void update(const CRegion& damage);
virtual SDMABUFAttrs dmabuf();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
bool good();
void updateTexture();
void closeFDs();
bool success = false;
private:
SDMABUFAttrs attrs;
struct {
CHyprSignalListener resourceDestroy;
} listeners;
};

View file

@ -0,0 +1,14 @@
#pragma once
enum eSurfaceRole {
SURFACE_ROLE_UNASSIGNED = 0,
SURFACE_ROLE_XDG_SHELL,
SURFACE_ROLE_LAYER_SHELL,
SURFACE_ROLE_EASTER_EGG,
SURFACE_ROLE_SUBSURFACE,
};
class ISurfaceRole {
public:
virtual eSurfaceRole role() = 0;
};

View file

@ -0,0 +1,43 @@
#include "WLBuffer.hpp"
#include "Buffer.hpp"
CWLBufferResource::CWLBufferResource(SP<CWlBuffer> resource_) : resource(resource_) {
if (!good())
return;
resource->setOnDestroy([this](CWlBuffer* r) {
if (buffer.expired())
return;
buffer->events.destroy.emit();
});
resource->setDestroy([this](CWlBuffer* r) {
if (buffer.expired())
return;
buffer->events.destroy.emit();
});
resource->setData(this);
}
bool CWLBufferResource::good() {
return resource->resource();
}
void CWLBufferResource::sendRelease() {
resource->sendRelease();
}
wl_resource* CWLBufferResource::getResource() {
return resource->resource();
}
SP<CWLBufferResource> CWLBufferResource::fromResource(wl_resource* res) {
auto data = (CWLBufferResource*)(((CWlBuffer*)wl_resource_get_user_data(res))->data());
return data ? data->self.lock() : nullptr;
}
SP<CWLBufferResource> CWLBufferResource::create(SP<CWlBuffer> resource) {
auto p = SP<CWLBufferResource>(new CWLBufferResource(resource));
p->self = p;
return p;
}

View file

@ -0,0 +1,31 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "../WaylandProtocol.hpp"
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
class IWLBuffer;
class CWLBufferResource {
public:
static SP<CWLBufferResource> create(SP<CWlBuffer> resource);
static SP<CWLBufferResource> fromResource(wl_resource* res);
bool good();
void sendRelease();
wl_resource* getResource();
WP<IWLBuffer> buffer;
WP<CWLBufferResource> self;
private:
CWLBufferResource(SP<CWlBuffer> resource_);
SP<CWlBuffer> resource;
friend class IWLBuffer;
};