input: Rewritten pointer constraints (#4889)

* rewritten constraints

* send pointer enter on activate if not pointer focus

* minor cleanup

* simulate movement on commit

* don't ignore oneshot prop

* various fixes

* dont send motion on confined

* update pos hint on region change
This commit is contained in:
Vaxry 2024-03-02 21:04:55 +00:00 committed by GitHub
parent 328ab43165
commit d72ea5f2a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 282 additions and 386 deletions

121
src/desktop/Constraint.cpp Normal file
View file

@ -0,0 +1,121 @@
#include "Constraint.hpp"
#include "WLSurface.hpp"
#include "../Compositor.hpp"
CConstraint::CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner) : m_pOwner(owner), m_pConstraint(constraint) {
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() {
if (active())
deactivate();
// 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) {
m_bHintSet = true;
m_vPositionHint = {m_pConstraint->current.cursor_hint.x, m_pConstraint->current.cursor_hint.y};
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;
wlr_pointer_constraint_v1_send_deactivated(m_pConstraint);
m_bActive = false;
g_pCompositor->warpCursorTo(logicPositionHint(), true);
if (m_pConstraint->lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT)
m_bDead = true;
}
void CConstraint::activate() {
if (m_bActive || m_bDead)
return;
// 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);
m_bActive = true;
}
bool CConstraint::active() {
return m_bActive;
}

View file

@ -0,0 +1,44 @@
#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,7 +103,10 @@ void CWLSurface::destroy() {
if (!m_pWLRSurface)
return;
m_pConstraint.reset();
hyprListener_destroy.removeCallback();
hyprListener_commit.removeCallback();
m_pWLRSurface->data = nullptr;
m_pWindowOwner = nullptr;
m_pLayerOwner = nullptr;
@ -123,6 +126,11 @@ void CWLSurface::destroy() {
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
}
static void onCommit(void* owner, void* data) {
const auto SURF = (CWLSurface*)owner;
SURF->onCommit();
}
void CWLSurface::init() {
if (!m_pWLRSurface)
return;
@ -133,6 +141,7 @@ void CWLSurface::init() {
hyprListener_destroy.initCallback(
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
hyprListener_commit.initCallback(&m_pWLRSurface->events.commit, ::onCommit, this, "CWLSurface");
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}
@ -172,3 +181,16 @@ std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
return {};
}
void CWLSurface::appendConstraint(wlr_pointer_constraint_v1* constraint) {
m_pConstraint = std::make_unique<CConstraint>(constraint, this);
}
void CWLSurface::onCommit() {
if (m_pConstraint)
m_pConstraint->onCommit();
}
CConstraint* CWLSurface::constraint() {
return m_pConstraint.get();
}

View file

@ -2,6 +2,7 @@
#include "../defines.hpp"
#include "../helpers/Region.hpp"
#include "Constraint.hpp"
class CWindow;
struct SLayerSurface;
@ -32,6 +33,7 @@ class CWLSurface {
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const;
void onCommit();
// getters for owners.
CWindow* getWindow();
@ -41,6 +43,8 @@ class CWLSurface {
// desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal();
void appendConstraint(wlr_pointer_constraint_v1* constraint);
CConstraint* constraint();
// allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false;
@ -72,6 +76,8 @@ class CWLSurface {
}
static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
if (!pSurface)
return nullptr;
return (CWLSurface*)pSurface->data;
}
@ -85,9 +91,15 @@ class CWLSurface {
CPopup* m_pPopupOwner = nullptr;
CSubsurface* m_pSubsurfaceOwner = nullptr;
void destroy();
void init();
bool desktopComponent();
//
std::unique_ptr<CConstraint> m_pConstraint;
void destroy();
void init();
bool desktopComponent();
DYNLISTENER(destroy);
DYNLISTENER(commit);
friend class CConstraint;
};