Directory: | ./ |
---|---|
File: | server/data_device.cpp |
Date: | 2024-01-22 17:25:27 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 91 | 98 | 92.9% |
Branches: | 33 | 48 | 68.8% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /******************************************************************** | ||
2 | Copyright © 2020 Roman Gilg <subdiff@gmail.com> | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 2.1 of the License, or (at your option) version 3, or any | ||
8 | later version accepted by the membership of KDE e.V. (or its | ||
9 | successor approved by the membership of KDE e.V.), which shall | ||
10 | act as a proxy defined in Section 6 of version 3 of the license. | ||
11 | |||
12 | This library is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | Lesser General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU Lesser General Public | ||
18 | License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
19 | *********************************************************************/ | ||
20 | #include "data_device.h" | ||
21 | |||
22 | #include "data_device_manager.h" | ||
23 | #include "data_offer_p.h" | ||
24 | #include "data_source.h" | ||
25 | #include "data_source_p.h" | ||
26 | #include "seat.h" | ||
27 | #include "selection_p.h" | ||
28 | #include "surface.h" | ||
29 | #include "surface_p.h" | ||
30 | |||
31 | #include "wayland/resource.h" | ||
32 | |||
33 | #include <wayland-server.h> | ||
34 | |||
35 | namespace Wrapland::Server | ||
36 | { | ||
37 | |||
38 | class data_device::Private : public Wayland::Resource<data_device> | ||
39 | { | ||
40 | public: | ||
41 | using source_res_t = Wrapland::Server::data_source_res; | ||
42 | |||
43 | Private(Client* client, uint32_t version, uint32_t id, Seat* seat, data_device* q_ptr); | ||
44 | ~Private() override; | ||
45 | |||
46 | data_offer* createDataOffer(data_source* source); | ||
47 | |||
48 | Seat* seat; | ||
49 | 32 | data_source* source = nullptr; | |
50 | 32 | Surface* surface = nullptr; | |
51 | 32 | Surface* icon = nullptr; | |
52 | |||
53 | 32 | data_source* selection = nullptr; | |
54 | QMetaObject::Connection selectionDestroyedConnection; | ||
55 | |||
56 | private: | ||
57 | static void startDragCallback(wl_client* wlClient, | ||
58 | wl_resource* wlResource, | ||
59 | wl_resource* wlSource, | ||
60 | wl_resource* wlOrigin, | ||
61 | wl_resource* wlIcon, | ||
62 | uint32_t serial); | ||
63 | static void set_selection_callback(wl_client* wlClient, | ||
64 | wl_resource* wlResource, | ||
65 | wl_resource* wlSource, | ||
66 | uint32_t id); | ||
67 | |||
68 | void startDrag(data_source* dataSource, Surface* origin, Surface* icon, quint32 serial) const; | ||
69 | |||
70 | static const struct wl_data_device_interface s_interface; | ||
71 | }; | ||
72 | |||
73 | const struct wl_data_device_interface data_device::Private::s_interface = { | ||
74 | startDragCallback, | ||
75 | set_selection_callback, | ||
76 | destroyCallback, | ||
77 | }; | ||
78 | |||
79 |
2/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
64 | data_device::Private::Private(Client* client, |
80 | uint32_t version, | ||
81 | uint32_t id, | ||
82 | Seat* seat, | ||
83 | data_device* q_ptr) | ||
84 | 64 | : Wayland::Resource<data_device>(client, | |
85 | 32 | version, | |
86 | 32 | id, | |
87 | &wl_data_device_interface, | ||
88 | &s_interface, | ||
89 | 32 | q_ptr) | |
90 | 32 | , seat(seat) | |
91 | 32 | { | |
92 | 32 | } | |
93 | |||
94 | 64 | data_device::Private::~Private() = default; | |
95 | |||
96 | 13 | void data_device::Private::startDragCallback([[maybe_unused]] wl_client* wlClient, | |
97 | wl_resource* wlResource, | ||
98 | wl_resource* wlSource, | ||
99 | wl_resource* wlOrigin, | ||
100 | wl_resource* wlIcon, | ||
101 | uint32_t serial) | ||
102 | { | ||
103 | 13 | auto priv = get_handle(wlResource)->d_ptr; | |
104 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
|
13 | auto source = wlSource ? Resource<data_source_res>::get_handle(wlSource)->src() : nullptr; |
105 | 13 | auto origin = Resource<Surface>::get_handle(wlOrigin); | |
106 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
|
13 | auto icon = wlIcon ? Resource<Surface>::get_handle(wlIcon) : nullptr; |
107 | |||
108 | 13 | priv->startDrag(source, origin, icon, serial); | |
109 | 13 | } | |
110 | |||
111 | 13 | void data_device::Private::startDrag(data_source* dataSource, | |
112 | Surface* origin, | ||
113 | Surface* _icon, | ||
114 | quint32 serial) const | ||
115 | { | ||
116 | // TODO(unknown author): verify serial | ||
117 | |||
118 | 13 | auto pointerGrab = false; | |
119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (seat->hasPointer()) { |
120 | 13 | auto& pointers = seat->pointers(); | |
121 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
|
13 | pointerGrab = pointers.has_implicit_grab(serial) && pointers.get_focus().surface == origin; |
122 | 13 | } | |
123 | |||
124 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 7 times.
|
13 | if (!pointerGrab) { |
125 | // Client doesn't have pointer grab. | ||
126 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | if (!seat->hasTouch()) { |
127 | // Client has no pointer grab and no touch capability. | ||
128 | 6 | return; | |
129 | } | ||
130 | 1 | auto& touches = seat->touches(); | |
131 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!touches.has_implicit_grab(serial) || touches.get_focus().surface != origin) { |
132 | // Client neither has pointer nor touch grab. No drag start allowed. | ||
133 | ✗ | return; | |
134 | } | ||
135 | 1 | } | |
136 | |||
137 | 7 | seat->drags().start(dataSource, origin, _icon, serial); | |
138 | 13 | } | |
139 | |||
140 | 18 | void data_device::Private::set_selection_callback(wl_client* /*wlClient*/, | |
141 | wl_resource* wlResource, | ||
142 | wl_resource* wlSource, | ||
143 | uint32_t /*id*/) | ||
144 | { | ||
145 | // TODO(unknown author): verify serial | ||
146 | 18 | auto handle = Resource::get_handle(wlResource); | |
147 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | auto source_res = wlSource ? Wayland::Resource<data_source_res>::get_handle(wlSource) : nullptr; |
148 | |||
149 | // TODO(romangg): move errors into Wayland namespace. | ||
150 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | if (source_res && source_res->src()->supported_dnd_actions() |
151 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | && wl_resource_get_version(wlSource) >= WL_DATA_SOURCE_ACTION_SINCE_VERSION) { |
152 | ✗ | wl_resource_post_error( | |
153 | ✗ | wlSource, WL_DATA_SOURCE_ERROR_INVALID_SOURCE, "Data source is for drag and drop"); | |
154 | ✗ | return; | |
155 | } | ||
156 | |||
157 | 18 | set_selection(handle, handle->d_ptr, wlSource); | |
158 | 18 | } | |
159 | |||
160 | 31 | data_offer* data_device::Private::createDataOffer(data_source* source) | |
161 | { | ||
162 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1 times.
|
31 | if (!source) { |
163 | // A data offer can only exist together with a source. | ||
164 | 1 | return nullptr; | |
165 | } | ||
166 | |||
167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | auto offer = new data_offer(client->handle, version, source); |
168 | |||
169 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | if (!offer->d_ptr->resource) { |
170 | // TODO(unknown author): send error? | ||
171 | ✗ | delete offer; | |
172 | ✗ | return nullptr; | |
173 | } | ||
174 | |||
175 | 30 | send<wl_data_device_send_data_offer>(offer->d_ptr->resource); | |
176 | 30 | offer->send_all_offers(); | |
177 | 30 | return offer; | |
178 | 31 | } | |
179 | |||
180 | 32 | data_device::data_device(Client* client, uint32_t version, uint32_t id, Seat* seat) | |
181 |
2/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
|
32 | : d_ptr(new Private(client, version, id, seat, this)) |
182 | 32 | { | |
183 | 32 | } | |
184 | |||
185 | 2 | Seat* data_device::seat() const | |
186 | { | ||
187 | 2 | return d_ptr->seat; | |
188 | } | ||
189 | |||
190 | 30 | data_source* data_device::selection() const | |
191 | { | ||
192 | 30 | return d_ptr->selection; | |
193 | } | ||
194 | |||
195 | 32 | void data_device::send_selection(data_source* source) | |
196 | { | ||
197 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 9 times.
|
32 | if (!source) { |
198 | 9 | send_clear_selection(); | |
199 | 9 | return; | |
200 | } | ||
201 | |||
202 | 23 | auto offer = d_ptr->createDataOffer(source); | |
203 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!offer) { |
204 | ✗ | return; | |
205 | } | ||
206 | |||
207 | 23 | d_ptr->send<wl_data_device_send_selection>(offer->d_ptr->resource); | |
208 | 32 | } | |
209 | |||
210 | 9 | void data_device::send_clear_selection() | |
211 | { | ||
212 | 9 | d_ptr->send<wl_data_device_send_selection>(nullptr); | |
213 | 9 | } | |
214 | |||
215 | 8 | data_offer* data_device::create_offer(data_source* source) | |
216 | { | ||
217 | 8 | return d_ptr->createDataOffer(source); | |
218 | } | ||
219 | |||
220 | 8 | void data_device::enter(uint32_t serial, Surface* surface, QPointF const& pos, data_offer* offer) | |
221 | { | ||
222 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | assert(surface); |
223 | 16 | d_ptr->send<wl_data_device_send_enter>(serial, | |
224 | 8 | surface->d_ptr->resource, | |
225 | 8 | wl_fixed_from_double(pos.x()), | |
226 | 8 | wl_fixed_from_double(pos.y()), | |
227 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
|
8 | offer ? offer->d_ptr->resource : nullptr); |
228 | 8 | } | |
229 | |||
230 | 4 | void data_device::motion(uint32_t time, QPointF const& pos) | |
231 | { | ||
232 | 8 | d_ptr->send<wl_data_device_send_motion>( | |
233 | 4 | time, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); | |
234 | 4 | } | |
235 | |||
236 | 2 | void data_device::leave() | |
237 | { | ||
238 | 2 | d_ptr->send<wl_data_device_send_leave>(); | |
239 | 2 | } | |
240 | |||
241 | 3 | void data_device::drop() | |
242 | { | ||
243 | 3 | d_ptr->send<wl_data_device_send_drop>(); | |
244 | 3 | } | |
245 | |||
246 | 50 | Client* data_device::client() const | |
247 | { | ||
248 | 50 | return d_ptr->client->handle; | |
249 | } | ||
250 | |||
251 | } | ||
252 |