pointer-constraints: move to new impl

This commit is contained in:
Vaxry 2024-04-26 23:55:41 +01:00
parent f94264928a
commit 25aec3ac8c
20 changed files with 404 additions and 590 deletions

View file

@ -14,6 +14,7 @@
#include <ranges>
#include "helpers/VarList.hpp"
#include "protocols/FractionalScale.hpp"
#include "protocols/PointerConstraints.hpp"
int handleCritSignal(int signo, void* data) {
Debug::log(LOG, "Hyprland received signal {}", signo);
@ -211,8 +212,6 @@ void CCompositor::initServer() {
m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay);
m_sWLRPointerConstraints = wlr_pointer_constraints_v1_create(m_sWLDisplay);
m_sWLRVKeyboardMgr = wlr_virtual_keyboard_manager_v1_create(m_sWLDisplay);
m_sWLRVirtPtrMgr = wlr_virtual_pointer_manager_v1_create(m_sWLDisplay);
@ -281,7 +280,6 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLROutputLayout->events.change, &Events::listen_change, m_sWLROutputLayout, "OutputLayout");
addWLSignal(&m_sWLROutputMgr->events.apply, &Events::listen_outputMgrApply, m_sWLROutputMgr, "OutputMgr");
addWLSignal(&m_sWLROutputMgr->events.test, &Events::listen_outputMgrTest, m_sWLROutputMgr, "OutputMgr");
addWLSignal(&m_sWLRPointerConstraints->events.new_constraint, &Events::listen_newConstraint, m_sWLRPointerConstraints, "PointerConstraints");
addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr");
addWLSignal(&m_sWLRVKeyboardMgr->events.new_virtual_keyboard, &Events::listen_newVirtualKeyboard, m_sWLRVKeyboardMgr, "VKeyboardMgr");
addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer");
@ -328,7 +326,6 @@ void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_change);
removeWLSignal(&Events::listen_outputMgrApply);
removeWLSignal(&Events::listen_outputMgrTest);
removeWLSignal(&Events::listen_newConstraint);
removeWLSignal(&Events::listen_newVirtPtr);
removeWLSignal(&Events::listen_newVirtualKeyboard);
removeWLSignal(&Events::listen_RendererDestroy);

View file

@ -62,7 +62,6 @@ class CCompositor {
wlr_presentation* m_sWLRPresentation;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
wlr_pointer_constraints_v1* m_sWLRPointerConstraints;
wlr_server_decoration_manager* m_sWLRServerDecoMgr;
wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr;
wlr_tablet_manager_v2* m_sWLRTabletManager;

View file

@ -1,142 +0,0 @@
#include "Constraint.hpp"
#include "WLSurface.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
CConstraint::CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner) : m_pOwner(owner), m_pConstraint(constraint) {
RASSERT(!constraint->data, "CConstraint: attempted to duplicate ownership");
constraint->data = this;
initSignals();
m_vCursorPosOnActivate = g_pInputManager->getMouseCoordsInternal();
g_pInputManager->m_vConstraints.push_back(this);
if (g_pCompositor->m_pLastFocus == m_pOwner->wlr())
activate();
}
CConstraint::~CConstraint() {
std::erase(g_pInputManager->m_vConstraints, this);
}
static void onConstraintDestroy(void* owner, void* data) {
const auto CONSTRAINT = (CConstraint*)owner;
CONSTRAINT->onDestroy();
}
static void onConstraintSetRegion(void* owner, void* data) {
const auto CONSTRAINT = (CConstraint*)owner;
CONSTRAINT->onSetRegion();
}
void CConstraint::initSignals() {
hyprListener_setConstraintRegion.initCallback(&m_pConstraint->events.set_region, ::onConstraintSetRegion, this, "CConstraint");
hyprListener_destroyConstraint.initCallback(&m_pConstraint->events.destroy, ::onConstraintDestroy, this, "CConstraint");
}
void CConstraint::onDestroy() {
hyprListener_setConstraintRegion.removeCallback();
hyprListener_destroyConstraint.removeCallback();
if (active() && isLocked())
g_pCompositor->warpCursorTo(logicPositionHint(), true);
// this is us
m_pOwner->m_pConstraint.reset();
}
void CConstraint::onSetRegion() {
if (!m_bActive)
return;
m_rRegion.set(&m_pConstraint->region);
m_vPositionHint = m_rRegion.closestPoint(m_vPositionHint);
g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss
}
void CConstraint::onCommit() {
if (!m_bActive)
return;
const auto COMMITTED = m_pConstraint->current.committed;
if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
m_bHintSet = true;
float scale = 1.f;
const auto PWINDOW = m_pOwner->getWindow();
if (PWINDOW) {
const auto ISXWL = PWINDOW->m_bIsX11;
scale = ISXWL && *PXWLFORCESCALEZERO ? PWINDOW->m_fX11SurfaceScaledBy : 1.f;
}
m_vPositionHint = {m_pConstraint->current.cursor_hint.x / scale, m_pConstraint->current.cursor_hint.y / scale};
g_pInputManager->simulateMouseMovement();
}
if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_REGION)
onSetRegion();
}
CRegion CConstraint::logicConstraintRegion() {
CRegion rg = m_rRegion;
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
rg.translate(CONSTRAINTPOS);
return rg;
}
CWLSurface* CConstraint::owner() {
return m_pOwner;
}
bool CConstraint::isLocked() {
return m_pConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED;
}
Vector2D CConstraint::logicPositionHint() {
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
return m_bHintSet ? CONSTRAINTPOS + m_vPositionHint : m_vCursorPosOnActivate;
}
void CConstraint::deactivate() {
if (!m_bActive)
return;
m_bActive = false;
if (isLocked())
g_pCompositor->warpCursorTo(logicPositionHint(), true);
if (m_pConstraint->lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT)
m_bDead = true;
wlr_pointer_constraint_v1_send_deactivated(m_pConstraint);
}
void CConstraint::activate() {
if (m_bActive || m_bDead)
return;
m_bActive = true;
// TODO: hack, probably not a super duper great idea
if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != m_pOwner->wlr()) {
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{};
wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, m_pOwner->wlr(), LOCAL.x, LOCAL.y);
}
g_pCompositor->warpCursorTo(logicPositionHint(), true);
wlr_pointer_constraint_v1_send_activated(m_pConstraint);
}
bool CConstraint::active() {
return m_bActive;
}

View file

@ -1,44 +0,0 @@
#pragma once
#include "../includes.hpp"
#include "../helpers/Region.hpp"
#include "../helpers/WLListener.hpp"
class CWLSurface;
class CConstraint {
public:
CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner);
~CConstraint();
void onCommit();
void onDestroy();
void onSetRegion();
CRegion logicConstraintRegion();
bool isLocked();
Vector2D logicPositionHint();
void deactivate();
void activate();
bool active();
CWLSurface* owner();
private:
bool m_bActive = false;
CWLSurface* m_pOwner = nullptr;
wlr_pointer_constraint_v1* m_pConstraint;
CRegion m_rRegion;
bool m_bHintSet = false;
Vector2D m_vPositionHint = {-1, -1};
Vector2D m_vCursorPosOnActivate = {-1, -1};
// for oneshot constraints that have been activated once
bool m_bDead = false;
DYNLISTENER(destroyConstraint);
DYNLISTENER(setConstraintRegion);
void initSignals();
};

View file

@ -103,6 +103,8 @@ void CWLSurface::destroy() {
if (!m_pWLRSurface)
return;
events.destroy.emit();
m_pConstraint.reset();
hyprListener_destroy.removeCallback();
@ -182,15 +184,14 @@ std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
return {};
}
void CWLSurface::appendConstraint(wlr_pointer_constraint_v1* constraint) {
m_pConstraint = std::make_unique<CConstraint>(constraint, this);
void CWLSurface::appendConstraint(std::weak_ptr<CPointerConstraint> constraint) {
m_pConstraint = constraint;
}
void CWLSurface::onCommit() {
if (m_pConstraint)
m_pConstraint->onCommit();
;
}
CConstraint* CWLSurface::constraint() {
return m_pConstraint.get();
std::shared_ptr<CPointerConstraint> CWLSurface::constraint() {
return m_pConstraint.lock();
}

View file

@ -2,12 +2,13 @@
#include "../defines.hpp"
#include "../helpers/Region.hpp"
#include "Constraint.hpp"
#include "../helpers/signal/Signal.hpp"
class CWindow;
struct SLayerSurface;
class CSubsurface;
class CPopup;
class CPointerConstraint;
class CWLSurface {
public:
@ -42,9 +43,9 @@ class CWLSurface {
CSubsurface* getSubsurface();
// desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal();
void appendConstraint(wlr_pointer_constraint_v1* constraint);
CConstraint* constraint();
std::optional<CBox> getSurfaceBoxGlobal();
void appendConstraint(std::weak_ptr<CPointerConstraint> constraint);
std::shared_ptr<CPointerConstraint> constraint();
// allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false;
@ -84,6 +85,10 @@ class CWLSurface {
// used by the alpha-modifier protocol
float m_pAlphaModifier = 1.F;
struct {
CSignal destroy;
} events;
private:
bool m_bInert = true;
@ -95,14 +100,14 @@ class CWLSurface {
CSubsurface* m_pSubsurfaceOwner = nullptr;
//
std::unique_ptr<CConstraint> m_pConstraint;
std::weak_ptr<CPointerConstraint> m_pConstraint;
void destroy();
void init();
bool desktopComponent();
void destroy();
void init();
bool desktopComponent();
DYNLISTENER(destroy);
DYNLISTENER(commit);
friend class CConstraint;
friend class CPointerConstraint;
};

View file

@ -93,21 +93,6 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
g_pInputManager->updateCapabilities();
}
void Events::listener_newConstraint(wl_listener* listener, void* data) {
const auto PCONSTRAINT = (wlr_pointer_constraint_v1*)data;
Debug::log(LOG, "New mouse constraint at {:x}", (uintptr_t)PCONSTRAINT);
const auto SURFACE = CWLSurface::surfaceFromWlr(PCONSTRAINT->surface);
if (!SURFACE) {
Debug::log(ERR, "Refusing a constraint from an unassigned wl_surface {:x}", (uintptr_t)PCONSTRAINT->surface);
return;
}
SURFACE->appendConstraint(PCONSTRAINT);
}
void Events::listener_newVirtPtr(wl_listener* listener, void* data) {
const auto EV = (wlr_virtual_pointer_v1_new_pointer_event*)data;
const auto POINTER = EV->new_pointer;

View file

@ -65,8 +65,6 @@ namespace Events {
DYNLISTENFUNC(keyboardMod);
DYNLISTENFUNC(keyboardDestroy);
LISTENER(newConstraint);
// Various
LISTENER(requestMouse);
LISTENER(requestSetSel);

View file

@ -8,7 +8,7 @@ CRegion::CRegion() {
pixman_region32_init(&m_rRegion);
}
CRegion::CRegion(pixman_region32_t* ref) {
CRegion::CRegion(const pixman_region32_t* const ref) {
pixman_region32_init(&m_rRegion);
pixman_region32_copy(&m_rRegion, ref);
}

View file

@ -11,7 +11,7 @@ class CRegion {
/* Create an empty region */
CRegion();
/* Create from a reference. Copies, does not own. */
CRegion(pixman_region32_t* ref);
CRegion(const pixman_region32_t* const ref);
/* Create from a box */
CRegion(double x, double y, double w, double h);
/* Create from a wlr_box */

View file

@ -80,7 +80,6 @@ extern "C" {
#include <wlr/render/egl.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/types/wlr_xdg_foreign_registry.h>
#include <wlr/types/wlr_xdg_foreign_v1.h>

View file

@ -14,6 +14,7 @@
#include "../protocols/ForeignToplevelWlr.hpp"
#include "../protocols/ShortcutsInhibit.hpp"
#include "../protocols/TextInputV3.hpp"
#include "../protocols/PointerConstraints.hpp"
#include "tearing-control-v1.hpp"
#include "fractional-scale-v1.hpp"
@ -29,6 +30,7 @@
#include "wlr-foreign-toplevel-management-unstable-v1.hpp"
#include "keyboard-shortcuts-inhibit-unstable-v1.hpp"
#include "text-input-unstable-v3.hpp"
#include "pointer-constraints-unstable-v1.hpp"
CProtocolManager::CProtocolManager() {
@ -46,6 +48,7 @@ CProtocolManager::CProtocolManager() {
PROTO::foreignToplevelWlr = std::make_unique<CForeignToplevelWlrProtocol>(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr");
PROTO::shortcutsInhibit = std::make_unique<CKeyboardShortcutsInhibitProtocol>(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit");
PROTO::textInputV3 = std::make_unique<CTextInputV3Protocol>(&zwp_text_input_manager_v3_interface, 1, "TextInputV3");
PROTO::constraints = std::make_unique<CPointerConstraintsProtocol>(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.

View file

@ -7,6 +7,7 @@
#include "../../protocols/CursorShape.hpp"
#include "../../protocols/IdleInhibit.hpp"
#include "../../protocols/RelativePointer.hpp"
#include "../../protocols/PointerConstraints.hpp"
CInputManager::CInputManager() {
m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) {
@ -193,7 +194,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return;
} else
Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF, (uintptr_t)CONSTRAINT);
Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF, (uintptr_t)CONSTRAINT.get());
}
// update stuff
@ -1298,16 +1299,26 @@ void CInputManager::unconstrainMouse() {
return;
for (auto& c : m_vConstraints) {
if (!c->active())
const auto C = c.lock();
if (!C)
continue;
c->deactivate();
if (!C->isActive())
continue;
C->deactivate();
}
}
bool CInputManager::isConstrained() {
for (auto& c : m_vConstraints) {
if (!c->active() || c->owner()->wlr() != g_pCompositor->m_pLastFocus)
const auto C = c.lock();
if (!C)
continue;
if (!C->isActive() || C->owner()->wlr() != g_pCompositor->m_pLastFocus)
continue;
return true;

View file

@ -8,7 +8,7 @@
#include "InputMethodRelay.hpp"
#include "../../helpers/signal/Listener.hpp"
class CConstraint;
class CPointerConstraint;
class CWindow;
class CIdleInhibitor;
@ -141,27 +141,28 @@ class CInputManager {
std::deque<SLayerSurface*> m_dExclusiveLSes;
// constraints
std::vector<CConstraint*> m_vConstraints;
std::vector<std::weak_ptr<CPointerConstraint>> m_vConstraints;
void newTabletTool(wlr_input_device*);
void newTabletPad(wlr_input_device*);
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
void newIdleInhibitor(std::any);
void recheckIdleInhibitorStatus();
//
void newTabletTool(wlr_input_device*);
void newTabletPad(wlr_input_device*);
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
void newIdleInhibitor(std::any);
void recheckIdleInhibitorStatus();
void onSwipeBegin(wlr_pointer_swipe_begin_event*);
void onSwipeEnd(wlr_pointer_swipe_end_event*);
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
void onSwipeBegin(wlr_pointer_swipe_begin_event*);
void onSwipeEnd(wlr_pointer_swipe_end_event*);
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
SSwipeGesture m_sActiveSwipe;
SSwipeGesture m_sActiveSwipe;
SKeyboard* m_pActiveKeyboard = nullptr;
SKeyboard* m_pActiveKeyboard = nullptr;
CTimer m_tmrLastCursorMovement;
CTimer m_tmrLastCursorMovement;
CInputMethodRelay m_sIMERelay;
CInputMethodRelay m_sIMERelay;
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
// for shared mods
uint32_t accumulateModsFromAllKBs();

View file

@ -0,0 +1,260 @@
#include "PointerConstraints.hpp"
#include "../desktop/WLSurface.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#define LOGM PROTO::constraints->protoLog
CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) :
resourceL(resource_), locked(true) {
if (!resource_->resource())
return;
resource_->setOnDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
resource_->setDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
pHLSurface = CWLSurface::surfaceFromWlr(surf);
if (!pHLSurface)
return;
if (region_)
region.set(wlr_region_from_resource(region_));
resource_->setSetRegion([this](CZwpLockedPointerV1* p, wl_resource* region) { onSetRegion(region); });
resource_->setSetCursorPositionHint([this](CZwpLockedPointerV1* p, wl_fixed_t x, wl_fixed_t y) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (!pHLSurface)
return;
hintSet = true;
float scale = 1.f;
const auto PWINDOW = pHLSurface->getWindow();
if (PWINDOW) {
const auto ISXWL = PWINDOW->m_bIsX11;
scale = ISXWL && *PXWLFORCESCALEZERO ? PWINDOW->m_fX11SurfaceScaledBy : 1.f;
}
positionHint = {wl_fixed_to_double(x) / scale, wl_fixed_to_double(y) / scale};
g_pInputManager->simulateMouseMovement();
});
sharedConstructions();
}
CPointerConstraint::CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) :
resourceC(resource_), locked(false) {
if (!resource_->resource())
return;
resource_->setOnDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
resource_->setDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); });
pHLSurface = CWLSurface::surfaceFromWlr(surf);
if (!pHLSurface)
return;
if (region_)
region.set(wlr_region_from_resource(region_));
resource_->setSetRegion([this](CZwpConfinedPointerV1* p, wl_resource* region) { onSetRegion(region); });
sharedConstructions();
}
CPointerConstraint::~CPointerConstraint() {
std::erase_if(g_pInputManager->m_vConstraints, [this](const auto& c) {
const auto SHP = c.lock();
return !SHP || SHP.get() == this;
});
if (pHLSurface)
pHLSurface->m_pConstraint.reset();
}
void CPointerConstraint::sharedConstructions() {
if (pHLSurface) {
listeners.destroySurface = pHLSurface->events.destroy.registerListener([this](std::any d) {
pHLSurface = nullptr;
if (active)
deactivate();
std::erase_if(g_pInputManager->m_vConstraints, [this](const auto& c) {
const auto SHP = c.lock();
return !SHP || SHP.get() == this;
});
});
}
cursorPosOnActivate = g_pInputManager->getMouseCoordsInternal();
if (g_pCompositor->m_pLastFocus == pHLSurface->wlr())
activate();
}
bool CPointerConstraint::good() {
return locked ? resourceL->resource() : resourceC->resource();
}
void CPointerConstraint::deactivate() {
if (!active)
return;
if (locked)
resourceL->sendUnlocked();
else
resourceC->sendUnconfined();
active = false;
if (locked)
g_pCompositor->warpCursorTo(logicPositionHint(), true);
if (lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT) {
dead = true;
// remove from inputmgr
std::erase_if(g_pInputManager->m_vConstraints, [this](const auto& c) {
const auto SHP = c.lock();
return !SHP || SHP.get() == this;
});
}
}
void CPointerConstraint::activate() {
if (dead || active)
return;
// TODO: hack, probably not a super duper great idea
if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != pHLSurface->wlr()) {
const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal();
const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{};
wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, pHLSurface->wlr(), LOCAL.x, LOCAL.y);
}
g_pCompositor->warpCursorTo(logicPositionHint(), true);
if (locked)
resourceL->sendLocked();
else
resourceC->sendConfined();
active = true;
g_pInputManager->simulateMouseMovement();
}
bool CPointerConstraint::isActive() {
return active;
}
void CPointerConstraint::onSetRegion(wl_resource* wlRegion) {
if (!wlRegion) {
region.clear();
return;
}
const auto REGION = wlr_region_from_resource(wlRegion);
region.set(REGION);
positionHint = region.closestPoint(positionHint);
g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss
}
CWLSurface* CPointerConstraint::owner() {
return pHLSurface;
}
CRegion CPointerConstraint::logicConstraintRegion() {
CRegion rg = region;
const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal();
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
rg.translate(CONSTRAINTPOS);
return rg;
}
bool CPointerConstraint::isLocked() {
return locked;
}
Vector2D CPointerConstraint::logicPositionHint() {
if (!pHLSurface)
return {};
const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal();
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
return hintSet ? CONSTRAINTPOS + positionHint : (locked ? CONSTRAINTPOS + SURFBOX->size() / 2.f : cursorPosOnActivate);
}
CPointerConstraintsProtocol::CPointerConstraintsProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CPointerConstraintsProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CZwpPointerConstraintsV1>(client, ver, id)).get();
RESOURCE->setOnDestroy([this](CZwpPointerConstraintsV1* p) { this->onManagerResourceDestroy(p->resource()); });
RESOURCE->setDestroy([this](CZwpPointerConstraintsV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setConfinePointer([this](CZwpPointerConstraintsV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* pointer, wl_resource* region,
zwpPointerConstraintsV1Lifetime lifetime) { this->onConfinePointer(pMgr, id, surface, pointer, region, lifetime); });
RESOURCE->setLockPointer([this](CZwpPointerConstraintsV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* pointer, wl_resource* region,
zwpPointerConstraintsV1Lifetime lifetime) { this->onLockPointer(pMgr, id, surface, pointer, region, lifetime); });
}
void CPointerConstraintsProtocol::onManagerResourceDestroy(wl_resource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
}
void CPointerConstraintsProtocol::destroyPointerConstraint(CPointerConstraint* hyprland🥚) {
std::erase_if(m_vConstraints, [&](const auto& other) { return other.get() == hyprland🥚; });
}
void CPointerConstraintsProtocol::onNewConstraint(SP<CPointerConstraint> constraint, CZwpPointerConstraintsV1* pMgr) {
if (!constraint->good()) {
LOGM(ERR, "Couldn't create constraint??");
wl_resource_post_no_memory(pMgr->resource());
m_vConstraints.pop_back();
return;
}
if (!constraint->owner()) {
LOGM(ERR, "New constraint has no CWLSurface owner??");
return;
}
const auto OWNER = constraint->owner();
const auto DUPES = std::count_if(m_vConstraints.begin(), m_vConstraints.end(), [OWNER](const auto& c) { return c->owner() == OWNER; });
if (DUPES > 1) {
LOGM(ERR, "Constraint for surface duped");
wl_resource_post_error(pMgr->resource(), ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED, "Surface already confined");
m_vConstraints.pop_back();
return;
}
OWNER->appendConstraint(constraint);
g_pInputManager->m_vConstraints.push_back(constraint);
}
void CPointerConstraintsProtocol::onLockPointer(CZwpPointerConstraintsV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* pointer, wl_resource* region,
zwpPointerConstraintsV1Lifetime lifetime) {
const auto CLIENT = wl_resource_get_client(pMgr->resource());
const auto RESOURCE = m_vConstraints.emplace_back(std::make_shared<CPointerConstraint>(
std::make_shared<CZwpLockedPointerV1>(CLIENT, wl_resource_get_version(pMgr->resource()), id), wlr_surface_from_resource(surface), region, lifetime));
onNewConstraint(RESOURCE, pMgr);
}
void CPointerConstraintsProtocol::onConfinePointer(CZwpPointerConstraintsV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* pointer, wl_resource* region,
zwpPointerConstraintsV1Lifetime lifetime) {
const auto CLIENT = wl_resource_get_client(pMgr->resource());
const auto RESOURCE = m_vConstraints.emplace_back(std::make_shared<CPointerConstraint>(
std::make_shared<CZwpConfinedPointerV1>(CLIENT, wl_resource_get_version(pMgr->resource()), id), wlr_surface_from_resource(surface), region, lifetime));
onNewConstraint(RESOURCE, pMgr);
}

View file

@ -0,0 +1,80 @@
#pragma once
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "pointer-constraints-unstable-v1.hpp"
#include "../helpers/Vector2D.hpp"
#include "../helpers/Region.hpp"
#include "../helpers/signal/Listener.hpp"
class CWLSurface;
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();
bool good();
void deactivate();
void activate();
bool isActive();
CWLSurface* owner();
CRegion logicConstraintRegion();
bool isLocked();
Vector2D logicPositionHint();
private:
SP<CZwpLockedPointerV1> resourceL;
SP<CZwpConfinedPointerV1> resourceC;
wl_client* pClient = nullptr;
CWLSurface* pHLSurface = nullptr;
CRegion region;
bool hintSet = false;
Vector2D positionHint = {-1, -1};
Vector2D cursorPosOnActivate = {-1, -1};
bool active = false;
bool locked = false;
bool dead = false;
zwpPointerConstraintsV1Lifetime lifetime = ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT;
void sharedConstructions();
void onSetRegion(wl_resource* region);
struct {
CHyprSignalListener destroySurface;
} listeners;
};
class CPointerConstraintsProtocol : public IWaylandProtocol {
public:
CPointerConstraintsProtocol(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 destroyPointerConstraint(CPointerConstraint* constraint);
void onLockPointer(CZwpPointerConstraintsV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* pointer, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime);
void onConfinePointer(CZwpPointerConstraintsV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* pointer, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime);
void onNewConstraint(SP<CPointerConstraint> constraint, CZwpPointerConstraintsV1* pMgr);
//
std::vector<UP<CZwpPointerConstraintsV1>> m_vManagers;
std::vector<SP<CPointerConstraint>> m_vConstraints;
friend class CPointerConstraint;
};
namespace PROTO {
inline UP<CPointerConstraintsProtocol> constraints;
};