alpha-modifier: add support for protocol

This commit is contained in:
Vaxry 2024-04-21 21:21:22 +01:00
parent 87173bd09d
commit f587c3e0ba
7 changed files with 187 additions and 8 deletions

View file

@ -268,6 +268,7 @@ protocolNew("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
protocolNew("unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "idle-inhibit-unstable-v1" false)
protocolNew("unstable/relative-pointer/relative-pointer-unstable-v1.xml" "relative-pointer-unstable-v1" false)
protocolNew("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "xdg-decoration-unstable-v1" false)
protocolNew("staging/alpha-modifier/alpha-modifier-v1.xml" "alpha-modifier-v1" false)
# tools
add_subdirectory(hyprctl)

View file

@ -46,6 +46,7 @@ new_protocols = [
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
[wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'],
]
wl_protos_src = []

View file

@ -81,6 +81,9 @@ class CWLSurface {
return (CWLSurface*)pSurface->data;
}
// used by the alpha-modifier protocol
float m_pAlphaModifier = 1.F;
private:
bool m_bInert = true;

View file

@ -7,6 +7,7 @@
#include "../protocols/IdleInhibit.hpp"
#include "../protocols/RelativePointer.hpp"
#include "../protocols/XDGDecoration.hpp"
#include "../protocols/AlphaModifier.hpp"
#include "tearing-control-v1.hpp"
#include "fractional-scale-v1.hpp"
@ -15,6 +16,7 @@
#include "idle-inhibit-unstable-v1.hpp"
#include "relative-pointer-unstable-v1.hpp"
#include "xdg-decoration-unstable-v1.hpp"
#include "alpha-modifier-v1.hpp"
CProtocolManager::CProtocolManager() {
@ -25,6 +27,7 @@ CProtocolManager::CProtocolManager() {
PROTO::idleInhibit = std::make_unique<CIdleInhibitProtocol>(&zwp_idle_inhibit_manager_v1_interface, 1, "IdleInhibit");
PROTO::relativePointer = std::make_unique<CRelativePointerProtocol>(&zwp_relative_pointer_manager_v1_interface, 1, "RelativePointer");
PROTO::xdgDecoration = std::make_unique<CXDGDecorationProtocol>(&zxdg_decoration_manager_v1_interface, 1, "XDGDecoration");
PROTO::alphaModifier = std::make_unique<CAlphaModifierProtocol>(&wp_alpha_modifier_v1_interface, 1, "AlphaModifier");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.

View file

@ -0,0 +1,121 @@
#include "AlphaModifier.hpp"
#include <algorithm>
#include "../desktop/WLSurface.hpp"
#include "../render/Renderer.hpp"
CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface_) : resource(resource_), pSurface(surface_) {
if (!resource->resource())
return;
resource->setDestroy([this](CWpAlphaModifierSurfaceV1* pMgr) {
PROTO::alphaModifier->destroyModifier(this);
setSurfaceAlpha(1.F);
});
resource->setOnDestroy([this](CWpAlphaModifierSurfaceV1* pMgr) {
PROTO::alphaModifier->destroyModifier(this);
setSurfaceAlpha(1.F);
});
hyprListener_surfaceDestroy.initCallback(
&surface_->events.destroy, [this](void* owner, void* data) { onSurfaceDestroy(); }, this, "CAlphaModifier");
resource->setSetMultiplier([this](CWpAlphaModifierSurfaceV1* mod, uint32_t alpha) {
if (!pSurface) {
wl_resource_post_error(mod->resource(), WP_ALPHA_MODIFIER_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone");
return;
}
float a = alpha / (float)UINT32_MAX;
setSurfaceAlpha(a);
});
}
CAlphaModifier::~CAlphaModifier() {
hyprListener_surfaceDestroy.removeCallback();
}
bool CAlphaModifier::good() {
return resource->resource();
}
wlr_surface* CAlphaModifier::getSurface() {
return pSurface;
}
void CAlphaModifier::setSurfaceAlpha(float a) {
CWLSurface* surf = CWLSurface::surfaceFromWlr(pSurface);
if (!surf) {
Debug::log(ERR, "Error in CAlphaModifier::setSurfaceAlpha: No CWLSurface for given surface??");
return;
}
surf->m_pAlphaModifier = a;
auto SURFBOX = surf->getSurfaceBoxGlobal();
if (SURFBOX.has_value())
g_pHyprRenderer->damageBox(&*SURFBOX);
}
void CAlphaModifier::onSurfaceDestroy() {
hyprListener_surfaceDestroy.removeCallback();
pSurface = nullptr;
}
CAlphaModifierProtocol::CAlphaModifierProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CAlphaModifierProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CWpAlphaModifierV1>(client, ver, id)).get();
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)); });
}
void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other->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) {
Debug::log(ERR, "CAlphaModifierProtocol::destroyModifier: dead resource but no deadptr???");
return;
}
m_mAlphaModifiers.erase(deadptr);
}
}
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface) {
if (m_mAlphaModifiers.contains(surface)) {
wl_resource_post_error(pMgr->resource(), WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present");
return;
}
const auto CLIENT = wl_resource_get_client(pMgr->resource());
const auto RESOURCE =
m_mAlphaModifiers
.emplace(surface, std::make_unique<CAlphaModifier>(std::make_shared<CWpAlphaModifierSurfaceV1>(CLIENT, wl_resource_get_version(pMgr->resource()), id), surface))
.first->second.get();
if (!RESOURCE->good()) {
wl_resource_post_no_memory(pMgr->resource());
m_mAlphaModifiers.erase(surface);
return;
}
}

View file

@ -0,0 +1,47 @@
#pragma once
#include <memory>
#include <vector>
#include <unordered_map>
#include "WaylandProtocol.hpp"
#include "alpha-modifier-v1.hpp"
class CAlphaModifier {
public:
CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface);
~CAlphaModifier();
bool good();
wlr_surface* getSurface();
void onSurfaceDestroy();
private:
SP<CWpAlphaModifierSurfaceV1> resource;
wlr_surface* pSurface = nullptr;
void setSurfaceAlpha(float a);
DYNLISTENER(surfaceDestroy);
};
class CAlphaModifierProtocol : public IWaylandProtocol {
public:
CAlphaModifierProtocol(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 onManagerResourceDestroy(wl_resource* res);
void destroyModifier(CAlphaModifier* decoration);
void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface);
//
std::vector<UP<CWpAlphaModifierV1>> m_vManagers;
std::unordered_map<wlr_surface*, UP<CAlphaModifier>> m_mAlphaModifiers; // xdg_toplevel -> deco
friend class CAlphaModifier;
};
namespace PROTO {
inline UP<CAlphaModifierProtocol> alphaModifier;
};

View file

@ -96,12 +96,15 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
double outputX = 0, outputY = 0;
wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, RDATA->pMonitor->output, &outputX, &outputY);
auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface);
const float ALPHA = RDATA->alpha * RDATA->fadeAlpha * (PSURFACE ? PSURFACE->m_pAlphaModifier : 1.F);
CBox windowBox;
if (RDATA->surface && surface == RDATA->surface) {
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, RDATA->w, RDATA->h};
// however, if surface buffer w / h < box, we need to adjust them
auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface);
const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr;
if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) {
@ -175,7 +178,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
rounding = 0;
const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface.wlr() == surface ? RDATA->pWindow->opaque() : false;
const bool CANDISABLEBLEND = RDATA->alpha * RDATA->fadeAlpha >= 1.f && rounding == 0 && (WINDOWOPAQUE || surface->opaque);
const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && (WINDOWOPAQUE || surface->opaque);
if (CANDISABLEBLEND)
g_pHyprOpenGL->blend(false);
@ -183,19 +186,19 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
g_pHyprOpenGL->blend(true);
if (RDATA->surface && surface == RDATA->surface) {
if (wlr_xwayland_surface_try_from_wlr_surface(surface) && !wlr_xwayland_surface_try_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 1.f) {
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
if (wlr_xwayland_surface_try_from_wlr_surface(surface) && !wlr_xwayland_surface_try_from_wlr_surface(surface)->has_alpha && ALPHA == 1.f) {
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true);
} else {
if (RDATA->blur)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha);
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha);
else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true);
}
} else {
if (RDATA->blur && RDATA->popup)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, true, RDATA->fadeAlpha);
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha);
else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true);
}
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {