aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/managers/SeatManager.hpp
blob: ccfe5e76e398603a6fd440f6c10fe83fdaa32be4 (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
#pragma once

#include <cstdint>
#include <wayland-server-protocol.h>
#include "../macros.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/math/Math.hpp"
#include "../protocols/types/DataDevice.hpp"
#include <vector>

constexpr size_t MAX_SERIAL_STORE_LEN = 100;

class CWLSurfaceResource;
class CWLSeatResource;
class IPointer;
class IKeyboard;

/*
    A seat grab defines a restricted set of surfaces that can be focused.
    Only one grab can be active at a time

    when a grab is removed, refocus() will happen

    Different from a constraint.

    When first set with setGrab, SeatManager will try to find a surface that is at the mouse pointer to focus,
    from first added to last added. If none are, first is focused.
*/
class CSeatGrab {
  public:
    bool accepts(SP<CWLSurfaceResource> surf);
    void add(SP<CWLSurfaceResource> surf);
    void remove(SP<CWLSurfaceResource> surf);
    void setCallback(std::function<void()> onEnd_);
    void clear();

    bool keyboard = false;
    bool pointer  = false;
    bool touch    = false;

    bool removeOnInput = true; // on hard input e.g. click outside, remove

  private:
    std::vector<WP<CWLSurfaceResource>> surfs;
    std::function<void()>               onEnd;
    friend class CSeatManager;
};

class CSeatManager {
  public:
    CSeatManager();

    void     updateCapabilities(uint32_t capabilities); // in IHID caps

    void     setMouse(SP<IPointer> mouse);
    void     setKeyboard(SP<IKeyboard> keeb);
    void     updateActiveKeyboardData(); // updates the clients with the keymap and repeat info

    void     setKeyboardFocus(SP<CWLSurfaceResource> surf);
    void     sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state);
    void     sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);

    void     setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D& local);
    void     sendPointerMotion(uint32_t timeMs, const Vector2D& local);
    void     sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state);
    void     sendPointerFrame();
    void     sendPointerFrame(WP<CWLSeatResource> pResource);
    void     sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, int32_t value120, wl_pointer_axis_source source,
                             wl_pointer_axis_relative_direction relative);

    void     sendTouchDown(SP<CWLSurfaceResource> surf, uint32_t timeMs, int32_t id, const Vector2D& local);
    void     sendTouchUp(uint32_t timeMs, int32_t id);
    void     sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local);
    void     sendTouchFrame();
    void     sendTouchCancel();
    void     sendTouchShape(int32_t id, const Vector2D& shape);
    void     sendTouchOrientation(int32_t id, double angle);

    void     resendEnterEvents();

    uint32_t nextSerial(SP<CWLSeatResource> seatResource);
    // pops the serial if it was valid, meaning it is consumed.
    bool                serialValid(SP<CWLSeatResource> seatResource, uint32_t serial);

    void                onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& hotspot);

    SP<CWLSeatResource> seatResourceForClient(wl_client* client);

    struct {
        WP<CWLSurfaceResource> keyboardFocus;
        WP<CWLSeatResource>    keyboardFocusResource;

        WP<CWLSurfaceResource> pointerFocus;
        WP<CWLSeatResource>    pointerFocusResource;

        WP<CWLSurfaceResource> touchFocus;
        WP<CWLSeatResource>    touchFocusResource;

        WP<CWLSurfaceResource> dndPointerFocus;
    } state;

    struct SSetCursorEvent {
        SP<CWLSurfaceResource> surf = nullptr;
        Vector2D               hotspot;
    };

    struct {
        CSignal keyboardFocusChange;
        CSignal pointerFocusChange;
        CSignal dndPointerFocusChange;
        CSignal touchFocusChange;
        CSignal setCursor; // SSetCursorEvent
        CSignal setSelection;
        CSignal setPrimarySelection;
    } events;

    struct {
        WP<IDataSource>     currentSelection;
        CHyprSignalListener destroySelection;
        WP<IDataSource>     currentPrimarySelection;
        CHyprSignalListener destroyPrimarySelection;
    } selection;

    void setCurrentSelection(SP<IDataSource> source);
    void setCurrentPrimarySelection(SP<IDataSource> source);

    // do not write to directly, use set...
    WP<IPointer>  mouse;
    WP<IKeyboard> keyboard;

    void          setGrab(SP<CSeatGrab> grab); // nullptr removes
    SP<CSeatGrab> seatGrab;

    bool          isPointerFrameSkipped = false;
    bool          isPointerFrameCommit  = false;

  private:
    struct SSeatResourceContainer {
        SSeatResourceContainer(SP<CWLSeatResource>);

        WP<CWLSeatResource>   resource;
        std::vector<uint32_t> serials; // old -> new

        struct {
            CHyprSignalListener destroy;
        } listeners;
    };

    std::vector<SP<SSeatResourceContainer>> seatResources;
    void                                    onNewSeatResource(SP<CWLSeatResource> resource);
    SP<SSeatResourceContainer>              containerForResource(SP<CWLSeatResource> seatResource);

    void                                    refocusGrab();

    struct {
        CHyprSignalListener newSeatResource;
        CHyprSignalListener keyboardSurfaceDestroy;
        CHyprSignalListener pointerSurfaceDestroy;
        CHyprSignalListener touchSurfaceDestroy;
    } listeners;

    Vector2D lastLocalCoords;
    int      touchLocks = 0; // we assume there aint like 20 touch devices at once...

    friend struct SSeatResourceContainer;
    friend class CSeatGrab;
};

inline UP<CSeatManager> g_pSeatManager;