summaryrefslogtreecommitdiff
path: root/src/desktop/Constraint.cpp
blob: 2109ef1c56af46315d5382d2c736ff1a29002af0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#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;

    m_bActive = false;

    wlr_pointer_constraint_v1_send_deactivated(m_pConstraint);

    if (isLocked())
        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;

    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;
}