summaryrefslogtreecommitdiff
path: root/src/protocols/core/DataDevice.hpp
blob: f3717f78ef429b1041de91b4814734fda78dbcd3 (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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#pragma once

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

#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 "../../helpers/time/Time.hpp"
#include "../types/DataDevice.hpp"
#include <hyprutils/os/FileDescriptor.hpp>

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

class CWLSurfaceResource;
class CMonitor;

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

    bool                             good();
    void                             sendData();

    virtual eDataSourceType          type();
    virtual SP<CWLDataOfferResource> getWayland();
    virtual SP<CX11DataOffer>        getX11();
    virtual SP<IDataSource>          getSource();

    WP<IDataSource>                  m_source;
    WP<CWLDataOfferResource>         m_self;

    bool                             m_dead     = false;
    bool                             m_accepted = false;
    bool                             m_recvd    = false;

  private:
    SP<CWlDataOffer> m_resource;

    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, Hyprutils::OS::CFileDescriptor 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
    virtual eDataSourceType          type();
    virtual void                     sendDndDropPerformed();
    virtual void                     sendDndAction(wl_data_device_manager_dnd_action a);

    bool                             m_used       = false;
    bool                             m_dnd        = false;
    bool                             m_dndSuccess = false;
    bool                             m_dropped    = false;

    WP<CWLDataDeviceResource>        m_device;
    WP<CWLDataSourceResource>        m_self;

    std::vector<std::string>         m_mimeTypes;
    uint32_t                         m_supportedActions = 0;

  private:
    SP<CWlDataSource> m_resource;

    friend class CWLDataDeviceProtocol;
};

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

    bool                              good();
    wl_client*                        client();

    virtual SP<CWLDataDeviceResource> getWayland();
    virtual SP<CX11DataDevice>        getX11();
    virtual void                      sendDataOffer(SP<IDataOffer> offer);
    virtual void                      sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<IDataOffer> offer);
    virtual void                      sendLeave();
    virtual void                      sendMotion(uint32_t timeMs, const Vector2D& local);
    virtual void                      sendDrop();
    virtual void                      sendSelection(SP<IDataOffer> offer);
    virtual eDataSourceType           type();

    WP<CWLDataDeviceResource>         m_self;

  private:
    SP<CWlDataDevice>      m_resource;
    wl_client*             m_client = nullptr;

    WP<CWLSurfaceResource> m_entered;

    friend class CWLDataDeviceProtocol;
};

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

    bool                                   good();

    WP<CWLDataDeviceResource>              m_device;
    std::vector<WP<CWLDataSourceResource>> m_sources;

  private:
    SP<CWlDataDeviceManager> m_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, const Time::steady_tp& when);
    // for inputmgr to force refocus
    // TODO: move handling to seatmgr
    bool dndActive();

    // called on an escape key pressed, for moments where it gets stuck
    void abortDndIfPresent();

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

    //
    std::vector<SP<CWLDataDeviceManagerResource>> m_managers;
    std::vector<SP<CWLDataDeviceResource>>        m_devices;
    std::vector<SP<CWLDataSourceResource>>        m_sources;
    std::vector<SP<CWLDataOfferResource>>         m_offers;

    //

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

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

        // for ending a dnd
        CHyprSignalListener mouseMove;
        CHyprSignalListener mouseButton;
        CHyprSignalListener touchUp;
        CHyprSignalListener touchMove;
        CHyprSignalListener tabletTip;
    } m_dnd;

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

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

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

    struct {
        CHyprSignalListener onKeyboardFocusChange;
        CHyprSignalListener onDndPointerFocusChange;
    } m_listeners;
};

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