1 /*
2     SPDX-FileCopyrightText: 2020 Adrien Faveraux <af@brain-networks.fr>
3     SPDX-FileCopyrightText: 2021 Francesco Sorrentino <francesco.sorr@gmail.com>
4 
5     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only
6 */
7 #include "client.h"
8 #include "primary_selection_p.h"
9 #include "seat_p.h"
10 #include "selection_device_p.h"
11 #include "selection_offer_p.h"
12 #include "selection_source_p.h"
13 
14 #include <unistd.h>
15 
16 namespace Wrapland::Server
17 {
18 
19 const struct zwp_primary_selection_device_v1_interface PrimarySelectionDevice::Private::s_interface
20     = {
21         set_selection_callback<Wayland::Resource<PrimarySelectionDevice>>,
22         destroyCallback,
23 };
24 
Private(Client * client,uint32_t version,uint32_t id,Seat * seat,PrimarySelectionDevice * qptr)25 PrimarySelectionDevice::Private::Private(Client* client,
26                                          uint32_t version,
27                                          uint32_t id,
28                                          Seat* seat,
29                                          PrimarySelectionDevice* qptr)
30     : Wayland::Resource<PrimarySelectionDevice>(client,
31                                                 version,
32                                                 id,
33                                                 &zwp_primary_selection_device_v1_interface,
34                                                 &s_interface,
35                                                 qptr)
36     , m_seat(seat)
37 {
38 }
39 
40 PrimarySelectionDevice::Private::~Private() = default;
41 
sendSelection(PrimarySelectionDevice * device)42 void PrimarySelectionDevice::sendSelection(PrimarySelectionDevice* device)
43 {
44     auto deviceSelection = device->selection();
45     if (!deviceSelection) {
46         sendClearSelection();
47         return;
48     }
49 
50     auto offer = d_ptr->sendDataOffer(deviceSelection);
51     if (!offer) {
52         return;
53     }
54 
55     d_ptr->send<zwp_primary_selection_device_v1_send_selection>(offer->d_ptr->resource());
56 }
57 
sendClearSelection()58 void PrimarySelectionDevice::sendClearSelection()
59 {
60     d_ptr->send<zwp_primary_selection_device_v1_send_selection>(nullptr);
61 }
62 
63 PrimarySelectionOffer*
sendDataOffer(PrimarySelectionSource * source)64 PrimarySelectionDevice::Private::sendDataOffer(PrimarySelectionSource* source)
65 {
66     if (!source) {
67         // A data offer can only exist together with a source.
68         return nullptr;
69     }
70 
71     auto offer = new PrimarySelectionOffer(client()->handle(), version(), source);
72 
73     if (!offer->d_ptr->resource()) {
74         delete offer;
75         return nullptr;
76     }
77 
78     send<zwp_primary_selection_device_v1_send_data_offer>(offer->d_ptr->resource());
79     offer->sendOffer();
80     return offer;
81 }
82 
PrimarySelectionDevice(Client * client,uint32_t version,uint32_t id,Seat * seat)83 PrimarySelectionDevice::PrimarySelectionDevice(Client* client,
84                                                uint32_t version,
85                                                uint32_t id,
86                                                Seat* seat)
87     : d_ptr(new Private(client, version, id, seat, this))
88 {
89 }
90 
91 PrimarySelectionDevice::~PrimarySelectionDevice() = default;
92 
selection()93 PrimarySelectionSource* PrimarySelectionDevice::selection()
94 {
95     return d_ptr->selection;
96 }
97 
client() const98 Client* PrimarySelectionDevice::client() const
99 {
100     return d_ptr->client()->handle();
101 }
102 
seat() const103 Seat* PrimarySelectionDevice::seat() const
104 {
105     return d_ptr->m_seat;
106 }
107 
108 const struct zwp_primary_selection_offer_v1_interface PrimarySelectionOffer::Private::s_interface
109     = {
110         receive_selection_offer<Wayland::Resource<PrimarySelectionOffer>>,
111         destroyCallback,
112 };
113 
Private(Client * client,uint32_t version,PrimarySelectionSource * source,PrimarySelectionOffer * qptr)114 PrimarySelectionOffer::Private::Private(Client* client,
115                                         uint32_t version,
116                                         PrimarySelectionSource* source,
117                                         PrimarySelectionOffer* qptr)
118     : Wayland::Resource<PrimarySelectionOffer>(client,
119                                                version,
120                                                0,
121                                                &zwp_primary_selection_offer_v1_interface,
122                                                &s_interface,
123                                                qptr)
124     , source(source)
125 {
126 }
127 
128 PrimarySelectionOffer::Private::~Private() = default;
129 
PrimarySelectionOffer(Client * client,uint32_t version,PrimarySelectionSource * source)130 PrimarySelectionOffer::PrimarySelectionOffer(Client* client,
131                                              uint32_t version,
132                                              PrimarySelectionSource* source)
133     : d_ptr(new Private(client, version, source, this))
134 {
135     assert(source);
136     QObject::connect(source,
137                      &PrimarySelectionSource::mimeTypeOffered,
138                      this,
139                      [this](std::string const& mimeType) {
140                          d_ptr->send<zwp_primary_selection_offer_v1_send_offer>(mimeType.c_str());
141                      });
142     QObject::connect(source, &PrimarySelectionSource::resourceDestroyed, this, [this] {
143         d_ptr->source = nullptr;
144     });
145 }
146 
147 PrimarySelectionOffer::~PrimarySelectionOffer() = default;
148 
sendOffer()149 void PrimarySelectionOffer::sendOffer()
150 {
151     for (auto const& mimeType : d_ptr->source->mimeTypes()) {
152         d_ptr->send<zwp_primary_selection_offer_v1_send_offer>(mimeType.c_str());
153     }
154 }
155 
156 const struct zwp_primary_selection_source_v1_interface PrimarySelectionSource::Private::s_interface
157     = {
158         add_offered_mime_type<Wayland::Resource<PrimarySelectionSource>>,
159         destroyCallback,
160 };
161 
Private(Client * client,uint32_t version,uint32_t id,PrimarySelectionSource * qptr)162 PrimarySelectionSource::Private::Private(Client* client,
163                                          uint32_t version,
164                                          uint32_t id,
165                                          PrimarySelectionSource* qptr)
166     : Wayland::Resource<PrimarySelectionSource>(client,
167                                                 version,
168                                                 id,
169                                                 &zwp_primary_selection_source_v1_interface,
170                                                 &s_interface,
171                                                 qptr)
172 {
173 }
174 
175 PrimarySelectionSource::Private::~Private() = default;
176 
PrimarySelectionSource(Client * client,uint32_t version,uint32_t id)177 PrimarySelectionSource::PrimarySelectionSource(Client* client, uint32_t version, uint32_t id)
178     : d_ptr(new Private(client, version, id, this))
179 {
180 }
181 
182 PrimarySelectionSource::~PrimarySelectionSource() = default;
183 
mimeTypes()184 std::vector<std::string> PrimarySelectionSource::mimeTypes()
185 {
186     return d_ptr->mimeTypes;
187 }
188 
cancel()189 void PrimarySelectionSource::cancel()
190 {
191     d_ptr->send<zwp_primary_selection_source_v1_send_cancelled>();
192     d_ptr->client()->flush();
193 }
requestData(std::string const & mimeType,qint32 fd)194 void PrimarySelectionSource::requestData(std::string const& mimeType, qint32 fd)
195 {
196     d_ptr->send<zwp_primary_selection_source_v1_send_send>(mimeType.c_str(), fd);
197     close(fd);
198 }
client() const199 Client* PrimarySelectionSource::client() const
200 {
201     return d_ptr->client()->handle();
202 }
203 
204 }
205