mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-22 22:09:49 +01:00
alpha-modifier: add support for protocol
This commit is contained in:
parent
87173bd09d
commit
f587c3e0ba
7 changed files with 187 additions and 8 deletions
|
@ -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)
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
121
src/protocols/AlphaModifier.cpp
Normal file
121
src/protocols/AlphaModifier.cpp
Normal 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;
|
||||
}
|
||||
}
|
47
src/protocols/AlphaModifier.hpp
Normal file
47
src/protocols/AlphaModifier.hpp
Normal 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;
|
||||
};
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue