tearing-control: hyprland impl (#5655)

* tearing: hl impl

* format
This commit is contained in:
Vaxry 2024-04-19 22:16:35 +01:00 committed by GitHub
parent 1016faea53
commit b52a49b4c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 207 additions and 74 deletions

View file

@ -0,0 +1,106 @@
#include "TearingControl.hpp"
#include "tearing-control-v1-protocol.h"
#include "../managers/ProtocolManager.hpp"
#include "../desktop/Window.hpp"
#include "../Compositor.hpp"
static void destroyManager(wl_client* client, wl_resource* resource) {
RESOURCE_OR_BAIL(PRESOURCE);
reinterpret_cast<CTearingControlProtocol*>(PRESOURCE->data())->onManagerResourceDestroy(resource);
}
static void getTearingControl(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* surface) {
RESOURCE_OR_BAIL(PRESOURCE);
reinterpret_cast<CTearingControlProtocol*>(PRESOURCE->data())->onGetController(client, resource, id, wlr_surface_from_resource(surface));
}
//
CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
g_pHookSystem->hookDynamic("destroyWindow", [this](void* self, SCallbackInfo& info, std::any param) { this->onWindowDestroy(std::any_cast<CWindow*>(param)); });
}
static const struct wp_tearing_control_manager_v1_interface MANAGER_IMPL = {
.destroy = ::destroyManager,
.get_tearing_control = ::getTearingControl,
};
void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CWaylandResource>(client, &wp_tearing_control_manager_v1_interface, ver, id)).get();
if (!RESOURCE->good()) {
Debug::log(LOG, "Couldn't bind TearingControlMgr");
return;
}
RESOURCE->setImplementation(&MANAGER_IMPL, nullptr);
RESOURCE->setData(this);
}
void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
}
void CTearingControlProtocol::onGetController(wl_client* client, wl_resource* resource, uint32_t id, wlr_surface* surf) {
const auto CONTROLLER = m_vTearingControllers
.emplace_back(std::make_unique<CTearingControl>(
std::make_shared<CWaylandResource>(client, &wp_tearing_control_v1_interface, wl_resource_get_version(resource), id), surf))
.get();
if (!CONTROLLER->good()) {
m_vTearingControllers.pop_back();
return;
}
}
void CTearingControlProtocol::onControllerDestroy(CTearingControl* control) {
std::erase_if(m_vTearingControllers, [control](const auto& other) { return other.get() == control; });
}
void CTearingControlProtocol::onWindowDestroy(CWindow* pWindow) {
for (auto& c : m_vTearingControllers) {
if (c->pWindow == pWindow)
c->pWindow = nullptr;
}
}
//
static void destroyController(wl_client* client, wl_resource* resource) {
RESOURCE_OR_BAIL(PRESOURCE);
PROTO::tearing->onControllerDestroy(reinterpret_cast<CTearingControl*>(PRESOURCE->data()));
}
static void setPresentationHint(wl_client* client, wl_resource* resource, uint32_t hint) {
RESOURCE_OR_BAIL(PRESOURCE);
reinterpret_cast<CTearingControl*>(PRESOURCE->data())->onHint(hint);
}
static const struct wp_tearing_control_v1_interface CONTROLLER_IMPL = {
.set_presentation_hint = ::setPresentationHint,
.destroy = ::destroyController,
};
CTearingControl::CTearingControl(SP<CWaylandResource> resource_, wlr_surface* surf_) : resource(resource_) {
resource->setImplementation(&CONTROLLER_IMPL, nullptr);
resource->setData(this);
resource->setOnDestroyHandler([](CWaylandResource* res) { PROTO::tearing->onControllerDestroy(reinterpret_cast<CTearingControl*>(res->data())); });
pWindow = g_pCompositor->getWindowFromSurface(surf_);
}
void CTearingControl::onHint(uint32_t hint_) {
hint = hint_ == WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC ? TEARING_VSYNC : TEARING_ASYNC;
updateWindow();
}
void CTearingControl::updateWindow() {
if (!pWindow)
return;
pWindow->m_bTearingHint = hint == TEARING_ASYNC;
}
bool CTearingControl::good() {
return resource->good();
}

View file

@ -0,0 +1,60 @@
#pragma once
#include <memory>
#include "WaylandProtocol.hpp"
class CWindow;
enum eTearingPresentationHint {
TEARING_VSYNC = 0,
TEARING_ASYNC,
};
class CTearingControlProtocol;
class CTearingControl {
public:
CTearingControl(SP<CWaylandResource> resource_, wlr_surface* surf_);
void onHint(uint32_t hint_);
bool good();
bool operator==(const wl_resource* other) const {
return other == resource->resource();
}
bool operator==(const CTearingControl* other) const {
return other->resource == resource;
}
private:
void updateWindow();
SP<CWaylandResource> resource;
CWindow* pWindow = nullptr;
eTearingPresentationHint hint = TEARING_VSYNC;
friend class CTearingControlProtocol;
};
class CTearingControlProtocol : public IWaylandProtocol {
public:
CTearingControlProtocol(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 onManagerResourceDestroy(wl_resource* res);
void onControllerDestroy(CTearingControl* control);
void onGetController(wl_client* client, wl_resource* resource, uint32_t id, wlr_surface* surf);
private:
void onWindowDestroy(CWindow* pWindow);
std::vector<UP<CWaylandResource>> m_vManagers;
std::vector<UP<CTearingControl>> m_vTearingControllers;
};
namespace PROTO {
inline UP<CTearingControlProtocol> tearing;
};

View file

@ -31,7 +31,14 @@ void CWaylandResource::markDefunct() {
Debug::log(TRACE, "[wl res {:x}] now defunct", (uintptr_t)m_pWLResource);
m_bDefunct = true;
wl_resource_set_user_data(m_pWLResource, nullptr);
// we call it here because we need defunct to be set to true.
// if this function destroys us, we can't call wl_resource_set_user_data or
// destroy the resource.
if (m_fOnDestroyHandler)
m_fOnDestroyHandler(this);
}
CWaylandResource::~CWaylandResource() {
@ -80,6 +87,10 @@ void* CWaylandResource::data() {
return m_pData;
}
void CWaylandResource::setOnDestroyHandler(std::function<void(CWaylandResource* res)> fn) {
m_fOnDestroyHandler = fn;
}
static void bindManagerInternal(wl_client* client, void* data, uint32_t ver, uint32_t id) {
((IWaylandProtocol*)data)->bindManager(client, data, ver, id);
}

View file

@ -2,11 +2,18 @@
#include "../defines.hpp"
#include <functional>
#define RESOURCE_OR_BAIL(resname) \
const auto resname = (CWaylandResource*)wl_resource_get_user_data(resource); \
if (!resname) \
return;
#define SP std::shared_ptr
#define UP std::unique_ptr
#define PROTO NProtocols
class CWaylandResource {
public:
CWaylandResource(wl_client* client, const wl_interface* wlInterface, uint32_t version, uint32_t id);
@ -24,12 +31,15 @@ class CWaylandResource {
void* data();
void setData(void* data);
void setOnDestroyHandler(std::function<void(CWaylandResource* res)> fn);
private:
bool m_bImplementationSet = false;
bool m_bDefunct = false; // m_liResourceDestroy fired
wl_client* m_pWLClient = nullptr;
wl_resource* m_pWLResource = nullptr;
void* m_pData = nullptr;
bool m_bImplementationSet = false;
bool m_bDefunct = false; // m_liResourceDestroy fired
wl_client* m_pWLClient = nullptr;
wl_resource* m_pWLResource = nullptr;
void* m_pData = nullptr;
std::function<void(CWaylandResource* res)> m_fOnDestroyHandler;
};
class IWaylandProtocol {