wayland/core: move to new impl (#6268)
* wayland/core/dmabuf: move to new impl it's the final countdown
This commit is contained in:
parent
c31d9ef417
commit
6967a31450
147 changed files with 5388 additions and 2226 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
454
src/protocols/LinuxDMABUF.cpp
Normal file
454
src/protocols/LinuxDMABUF.cpp
Normal 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; });
|
||||
}
|
||||
138
src/protocols/LinuxDMABUF.hpp
Normal file
138
src/protocols/LinuxDMABUF.hpp
Normal 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
133
src/protocols/MesaDRM.cpp
Normal 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
60
src/protocols/MesaDRM.hpp
Normal 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;
|
||||
};
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
126
src/protocols/Viewporter.cpp
Normal file
126
src/protocols/Viewporter.cpp
Normal 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; });
|
||||
}
|
||||
55
src/protocols/Viewporter.hpp
Normal file
55
src/protocols/Viewporter.hpp
Normal 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;
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
467
src/protocols/core/Compositor.cpp
Normal file
467
src/protocols/core/Compositor.cpp
Normal 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; });
|
||||
}
|
||||
175
src/protocols/core/Compositor.hpp
Normal file
175
src/protocols/core/Compositor.hpp
Normal 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;
|
||||
};
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
107
src/protocols/core/Output.cpp
Normal file
107
src/protocols/core/Output.cpp
Normal 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();
|
||||
}
|
||||
61
src/protocols/core/Output.hpp
Normal file
61
src/protocols/core/Output.hpp
Normal 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;
|
||||
};
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
214
src/protocols/core/Shm.cpp
Normal 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
111
src/protocols/core/Shm.hpp
Normal 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;
|
||||
};
|
||||
192
src/protocols/core/Subcompositor.cpp
Normal file
192
src/protocols/core/Subcompositor.cpp
Normal 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; });
|
||||
}
|
||||
82
src/protocols/core/Subcompositor.hpp
Normal file
82
src/protocols/core/Subcompositor.hpp
Normal 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;
|
||||
};
|
||||
41
src/protocols/types/Buffer.cpp
Normal file
41
src/protocols/types/Buffer.cpp
Normal 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;
|
||||
}
|
||||
74
src/protocols/types/Buffer.hpp
Normal file
74
src/protocols/types/Buffer.hpp
Normal 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;
|
||||
};
|
||||
75
src/protocols/types/DMABuffer.cpp
Normal file
75
src/protocols/types/DMABuffer.cpp
Normal 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;
|
||||
}
|
||||
28
src/protocols/types/DMABuffer.hpp
Normal file
28
src/protocols/types/DMABuffer.hpp
Normal 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;
|
||||
};
|
||||
14
src/protocols/types/SurfaceRole.hpp
Normal file
14
src/protocols/types/SurfaceRole.hpp
Normal 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;
|
||||
};
|
||||
43
src/protocols/types/WLBuffer.cpp
Normal file
43
src/protocols/types/WLBuffer.cpp
Normal 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;
|
||||
}
|
||||
31
src/protocols/types/WLBuffer.hpp
Normal file
31
src/protocols/types/WLBuffer.hpp
Normal 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;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue