summaryrefslogtreecommitdiff
path: root/src/managers/PointerManager.hpp
blob: d60903a625c5e9c40f1cf19ee9a983908291254c (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#pragma once

#include "../devices/IPointer.hpp"
#include "../devices/ITouch.hpp"
#include "../devices/Tablet.hpp"
#include "../helpers/math/Math.hpp"
#include "../desktop/view/WLSurface.hpp"
#include "../helpers/sync/SyncTimeline.hpp"
#include "../helpers/time/Time.hpp"
#include <tuple>

class CMonitor;
class IHID;
class CTexture;

AQUAMARINE_FORWARD(IBuffer);

/*
    The naming here is a bit confusing.
    CPointerManager manages the _position_ and _displaying_ of the cursor,
    but the CCursorManager _only_ manages the actual image (texture) and size
    of the cursor.
*/

class CPointerManager {
  public:
    CPointerManager();

    void attachPointer(SP<IPointer> pointer);
    void attachTouch(SP<ITouch> touch);
    void attachTablet(SP<CTablet> tablet);

    void detachPointer(SP<IPointer> pointer);
    void detachTouch(SP<ITouch> touch);
    void detachTablet(SP<CTablet> tablet);

    // only clamps to the layout.
    void warpTo(const Vector2D& logical);
    void move(const Vector2D& deltaLogical);
    void warpAbsolute(Vector2D abs, SP<IHID> dev);

    void setCursorBuffer(SP<Aquamarine::IBuffer> buf, const Vector2D& hotspot, const float& scale);
    void setCursorSurface(SP<Desktop::View::CWLSurface> buf, const Vector2D& hotspot);
    void resetCursorImage(bool apply = true);

    void lockSoftwareForMonitor(PHLMONITOR pMonitor);
    void unlockSoftwareForMonitor(PHLMONITOR pMonitor);
    void lockSoftwareAll();
    void unlockSoftwareAll();
    bool softwareLockedFor(PHLMONITOR pMonitor);

    void renderSoftwareCursorsFor(PHLMONITOR pMonitor, const Time::steady_tp& now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */,
                                  bool forceRender = false);

    // this is needed e.g. during screensharing where
    // the software cursors aren't locked during the cursor move, but they
    // are rendered later.
    void damageCursor(PHLMONITOR pMonitor, bool skipFrameSchedule = false);

    //
    Vector2D position();
    Vector2D cursorSizeLogical();

    void     recheckEnteredOutputs();

  private:
    void recheckPointerPosition();
    void onMonitorLayoutChange();
    void onMonitorDisconnect();
    void updateCursorBackend();
    void onCursorMoved();
    bool hasCursor();
    void damageIfSoftware();

    // closest valid point to a given one
    Vector2D closestValid(const Vector2D& pos);

    // returns the thing in device coordinates. Is NOT offset by the hotspot, relies on set_cursor with hotspot.
    Vector2D getCursorPosForMonitor(PHLMONITOR pMonitor);
    // returns the thing in logical coordinates of the monitor
    CBox getCursorBoxLogicalForMonitor(PHLMONITOR pMonitor);
    // returns the thing in global coords
    CBox         getCursorBoxGlobal();

    Vector2D     transformedHotspot(PHLMONITOR pMonitor);

    SP<CTexture> getCurrentCursorTexture();

    struct SPointerListener {
        CHyprSignalListener destroy;
        CHyprSignalListener motion;
        CHyprSignalListener motionAbsolute;
        CHyprSignalListener button;
        CHyprSignalListener axis;

        CHyprSignalListener swipeBegin;
        CHyprSignalListener swipeEnd;
        CHyprSignalListener swipeUpdate;

        CHyprSignalListener pinchBegin;
        CHyprSignalListener pinchEnd;
        CHyprSignalListener pinchUpdate;

        CHyprSignalListener holdBegin;
        CHyprSignalListener holdEnd;

        WP<IPointer>        pointer;
    };
    std::vector<SP<SPointerListener>> m_pointerListeners;

    struct STouchListener {
        CHyprSignalListener destroy;
        CHyprSignalListener down;
        CHyprSignalListener up;
        CHyprSignalListener motion;
        CHyprSignalListener cancel;
        CHyprSignalListener frame;

        WP<ITouch>          touch;
    };
    std::vector<SP<STouchListener>> m_touchListeners;

    struct STabletListener {
        CHyprSignalListener destroy;
        CHyprSignalListener axis;
        CHyprSignalListener proximity;
        CHyprSignalListener tip;
        CHyprSignalListener button;

        WP<CTablet>         tablet;
    };
    std::vector<SP<STabletListener>> m_tabletListeners;

    struct {
        std::vector<CBox> monitorBoxes;
    } m_currentMonitorLayout;

    struct {
        SP<Aquamarine::IBuffer>       pBuffer;
        SP<CTexture>                  bufferTex;
        WP<Desktop::View::CWLSurface> surface;

        Vector2D                      hotspot;
        Vector2D                      size;
        float                         scale = 1.F;

        CHyprSignalListener           destroySurface;
        CHyprSignalListener           commitSurface;
    } m_currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors

    Vector2D m_pointerPos = {0, 0};

    struct SMonitorPointerState {
        SMonitorPointerState(const PHLMONITOR& m) : monitor(m) {}
        ~SMonitorPointerState() = default;

        PHLMONITORREF           monitor;

        int                     softwareLocks  = 0;
        bool                    hardwareFailed = false;
        CBox                    box; // logical
        bool                    entered        = false;
        bool                    hwApplied      = false;
        bool                    cursorRendered = false;

        SP<Aquamarine::IBuffer> cursorFrontBuffer;
    };

    std::vector<SP<SMonitorPointerState>> m_monitorStates;
    SP<SMonitorPointerState>              stateFor(PHLMONITOR mon);
    bool                                  attemptHardwareCursor(SP<SMonitorPointerState> state);
    SP<Aquamarine::IBuffer>               renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
    bool                                  setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf);

    struct {
        SP<HOOK_CALLBACK_FN> monitorAdded;
        SP<HOOK_CALLBACK_FN> monitorPreRender;
    } m_hooks;
};

inline UP<CPointerManager> g_pPointerManager;