aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/protocols/core/DataDevice.hpp
blob: 81ca1b11b0e79d6263cb02b60e1d1d1435e8059b (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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#pragma once

/*
    Implementations for:
     - wl_data_offer
     - wl_data_source
     - wl_data_device
     - wl_data_device_manager
*/

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

class CWLDataDeviceResource;
class CWLDataDeviceManagerResource;
class CWLDataSourceResource;
class CWLDataOfferResource;

class CWLSurfaceResource;
class CMonitor;

class CWLDataOfferResource {
  public:
    CWLDataOfferResource(SP<CWlDataOffer> resource_, SP<IDataSource> source_);
    ~CWLDataOfferResource();

    bool            good();
    void            sendData();

    WP<IDataSource> source;

    bool            dead     = false;
    bool            accepted = false;
    bool            recvd    = false;

    uint32_t        actions = 0;

  private:
    SP<CWlDataOffer> resource;
    wl_client*       pClient = nullptr;

    friend class CWLDataDeviceResource;
};

class CWLDataSourceResource : public IDataSource {
  public:
    CWLDataSourceResource(SP<CWlDataSource> resource_, SP<CWLDataDeviceResource> device_);
    ~CWLDataSourceResource();
    static SP<CWLDataSourceResource> fromResource(wl_resource*);

    bool                             good();

    virtual std::vector<std::string> mimes();
    virtual void                     send(const std::string& mime, uint32_t fd);
    virtual void                     accepted(const std::string& mime);
    virtual void                     cancelled();
    virtual bool                     hasDnd();
    virtual bool                     dndDone();
    virtual void                     error(uint32_t code, const std::string& msg);
    virtual void                     sendDndFinished();
    virtual uint32_t                 actions(); // wl_data_device_manager.dnd_action

    void                             sendDndDropPerformed();
    void                             sendDndAction(wl_data_device_manager_dnd_action a);

    bool                             used       = false;
    bool                             dnd        = false;
    bool                             dndSuccess = false;
    bool                             dropped    = false;

    WP<CWLDataDeviceResource>        device;
    WP<CWLDataSourceResource>        self;

    std::vector<std::string>         mimeTypes;
    uint32_t                         supportedActions = 0;

  private:
    SP<CWlDataSource> resource;
    wl_client*        pClient = nullptr;

    friend class CWLDataDeviceProtocol;
};

class CWLDataDeviceResource {
  public:
    CWLDataDeviceResource(SP<CWlDataDevice> resource_);

    bool                      good();
    wl_client*                client();

    void                      sendDataOffer(SP<CWLDataOfferResource> offer);
    void                      sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<CWLDataOfferResource> offer);
    void                      sendLeave();
    void                      sendMotion(uint32_t timeMs, const Vector2D& local);
    void                      sendDrop();
    void                      sendSelection(SP<CWLDataOfferResource> offer);

    WP<CWLDataDeviceResource> self;

  private:
    SP<CWlDataDevice> resource;
    wl_client*        pClient = nullptr;

    friend class CWLDataDeviceProtocol;
};

class CWLDataDeviceManagerResource {
  public:
    CWLDataDeviceManagerResource(SP<CWlDataDeviceManager> resource_);

    bool                                   good();

    WP<CWLDataDeviceResource>              device;
    std::vector<WP<CWLDataSourceResource>> sources;

  private:
    SP<CWlDataDeviceManager> resource;
};

class CWLDataDeviceProtocol : public IWaylandProtocol {
  public:
    CWLDataDeviceProtocol(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);

    // renders and damages the dnd icon, if present
    void renderDND(PHLMONITOR pMonitor, timespec* when);
    // for inputmgr to force refocus
    // TODO: move handling to seatmgr
    bool dndActive();

  private:
    void destroyResource(CWLDataDeviceManagerResource* resource);
    void destroyResource(CWLDataDeviceResource* resource);
    void destroyResource(CWLDataSourceResource* resource);
    void destroyResource(CWLDataOfferResource* resource);

    //
    std::vector<SP<CWLDataDeviceManagerResource>> m_vManagers;
    std::vector<SP<CWLDataDeviceResource>>        m_vDevices;
    std::vector<SP<CWLDataSourceResource>>        m_vSources;
    std::vector<SP<CWLDataOfferResource>>         m_vOffers;

    //

    void onDestroyDataSource(WP<CWLDataSourceResource> source);
    void setSelection(SP<IDataSource> source);
    void sendSelectionToDevice(SP<CWLDataDeviceResource> dev, SP<IDataSource> sel);
    void updateSelection();
    void onKeyboardFocus();

    struct {
        WP<CWLDataDeviceResource> focusedDevice;
        WP<CWLDataSourceResource> currentSource;
        WP<CWLSurfaceResource>    dndSurface;
        WP<CWLSurfaceResource>    originSurface;
        bool                      overriddenCursor = false;
        CHyprSignalListener       dndSurfaceDestroy;
        CHyprSignalListener       dndSurfaceCommit;

        // for ending a dnd
        SP<HOOK_CALLBACK_FN> mouseMove;
        SP<HOOK_CALLBACK_FN> mouseButton;
        SP<HOOK_CALLBACK_FN> touchUp;
        SP<HOOK_CALLBACK_FN> touchMove;
    } dnd;

    void abortDrag();
    void initiateDrag(WP<CWLDataSourceResource> currentSource, SP<CWLSurfaceResource> dragSurface, SP<CWLSurfaceResource> origin);
    void updateDrag();
    void dropDrag();
    void completeDrag();
    void resetDndState();
    bool wasDragSuccessful();

    //
    SP<CWLDataDeviceResource> dataDeviceForClient(wl_client*);

    friend class CSeatManager;
    friend class CWLDataDeviceManagerResource;
    friend class CWLDataDeviceResource;
    friend class CWLDataSourceResource;
    friend class CWLDataOfferResource;

    struct {
        CHyprSignalListener onKeyboardFocusChange;
    } listeners;
};

namespace PROTO {
    inline UP<CWLDataDeviceProtocol> data;
};