fdd3657163c4658b4c8b89c423bb0839f386c37a
[platform/core/uifw/dali-adaptor.git] / dali / internal / clipboard / tizen-wayland / clipboard-impl-ecore-wl.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/clipboard/common/clipboard-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/singleton-service.h>
23 #include <dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h>
24 #include <dali/integration-api/debug.h>
25 #include <unistd.h>
26 #include <unordered_map>
27
28 namespace Dali
29 {
30 namespace Internal
31 {
32 namespace Adaptor
33 {
34 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event);
35 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event);
36 static Eina_Bool EcoreEventSelectionOffer(void* data, int type, void* event);
37
38 struct Clipboard::Impl
39 {
40   Impl()
41   {
42     mSendHandler      = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, this);
43     mReceiveHandler   = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, EcoreEventOfferDataReady, this);
44     mSelectionHanlder = ecore_event_handler_add(ECORE_WL2_EVENT_SEAT_SELECTION, EcoreEventSelectionOffer, this);
45   }
46   ~Impl()
47   {
48     ecore_event_handler_del(mSendHandler);
49     ecore_event_handler_del(mReceiveHandler);
50     ecore_event_handler_del(mSelectionHanlder);
51   }
52
53   bool SetData(const Dali::Clipboard::ClipData& clipData)
54   {
55     mMimeType = clipData.GetMimeType();
56     mData     = clipData.GetData();
57
58     if(mData.empty())
59     {
60       DALI_LOG_ERROR("ClipData is empty, return false.\n");
61       return false;
62     }
63
64     const char* mimeTypes[2];
65     mimeTypes[0] = mMimeType.c_str();
66     mimeTypes[1] = nullptr;
67
68     Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
69     Ecore_Wl2_Input* input     = ecore_wl2_input_default_input_get(display);
70     mSerial                    = ecore_wl2_dnd_selection_set(input, mimeTypes);
71     DALI_LOG_RELEASE_INFO("selection_set success, serial:%u, type:%s, data:%s\n", mSerial, mMimeType.c_str(), mData.c_str());
72
73     return true;
74   }
75
76   uint32_t GetData(const std::string &mimeType)
77   {
78     const char* type = mimeType.c_str();
79     if(!type)
80     {
81       DALI_LOG_ERROR("no request type, type is null.\n");
82       return 0u;
83     }
84
85     Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
86     Ecore_Wl2_Input*   input   = ecore_wl2_input_default_input_get(display);
87     Ecore_Wl2_Offer*   offer   = ecore_wl2_dnd_selection_get(input);
88
89     if(!offer)
90     {
91       DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
92       return 0u;
93     }
94
95     Eina_Array*  availableTypes = ecore_wl2_offer_mimes_get(offer);
96     char*        selectedType   = nullptr;
97     unsigned int typeCount      = (unsigned int)eina_array_count((Eina_Array *)availableTypes);
98
99     for(unsigned int i = 0; i < typeCount && !selectedType; ++i)
100     {
101       char* availableType = (char*)eina_array_data_get((Eina_Array *)availableTypes, i);
102       if(!mimeType.compare(availableType))
103       {
104         selectedType = availableType;
105         break;
106       }
107     }
108
109     if(!selectedType)
110     {
111       DALI_LOG_ERROR("no matching type, num of available types:%u, request type:%s\n", typeCount, mimeType.c_str());
112       for(unsigned int i = 0; i < typeCount && !selectedType; ++i)
113       {
114         DALI_LOG_ERROR("available type[%u]:%s\n", i, (char*)eina_array_data_get((Eina_Array *)availableTypes, i));
115       }
116       return 0u;
117     }
118
119     mDataId++;
120     mDataRequestIds.push_back(mDataId);
121     mDataRequestItems[mDataId] = std::make_pair(mimeType, offer);
122
123     DALI_LOG_RELEASE_INFO("offer_receive, id:%u, request type:%s\n", mDataId, mimeType.c_str());
124     ecore_wl2_offer_receive(offer, const_cast<char*>(type));
125     ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
126     return mDataId;
127   }
128
129   void SendData(void* event)
130   {
131     Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
132
133     if(ev->serial != mSerial)
134     {
135       return;
136     }
137
138     // no matching mime type.
139     if(mMimeType.compare(ev->type))
140     {
141       auto it = mDataRequestIds.begin();
142       while(it != mDataRequestIds.end())
143       {
144         uint32_t dataRequestId = *it;
145         auto     item          = mDataRequestItems.find(dataRequestId);
146         if(item != mDataRequestItems.end())
147         {
148           std::string mimeType = static_cast<std::string>(item->second.first);
149           if(!mimeType.compare(ev->type))
150           {
151             mDataRequestItems.erase(dataRequestId);
152             it = mDataRequestIds.erase(it);
153             DALI_LOG_ERROR("no matching type, empty signal emit, request type:%s, available type:%s\n", ev->type, mMimeType.c_str());
154             mDataReceivedSignal.Emit(dataRequestId, "", "");
155           }
156           else
157           {
158             ++it;
159           }
160         }
161       }
162       return;
163     }
164
165     size_t dataLength = strlen(mData.c_str());
166     size_t bufferSize = dataLength + 1u;
167
168     char* buffer = new char[bufferSize];
169     if(!buffer)
170     {
171       return;
172     }
173
174     memcpy(buffer, mData.c_str(), dataLength);
175     buffer[dataLength] = '\0';
176
177     auto ret = write(ev->fd, buffer, bufferSize);
178     if(DALI_UNLIKELY(ret != static_cast<ssize_t>(bufferSize)))
179     {
180       DALI_LOG_ERROR("write(ev->fd) return %zd\n", ret);
181     }
182
183     close(ev->fd);
184     delete[] buffer;
185
186     DALI_LOG_RELEASE_INFO("send data, type:%s, data:%s \n", mMimeType.c_str(), mData.c_str());
187     mDataSentSignal.Emit(ev->type, mData.c_str());
188   }
189
190   void ReceiveData(void* event)
191   {
192     Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
193
194     if(ev == nullptr)
195     {
196       DALI_LOG_ERROR("ev is nullptr.\n");
197       return;
198     }
199
200     if(ev->data == nullptr || ev->len < 1)
201     {
202       DALI_LOG_ERROR("no selection data.\n");
203       return;
204     }
205
206     size_t      dataLength = strlen(ev->data);
207     size_t      bufferSize = static_cast<size_t>(ev->len);
208     std::string content;
209
210     if(dataLength < bufferSize)
211     {
212       content.append(ev->data, dataLength);
213     }
214     else
215     {
216       content.append(ev->data, bufferSize);
217     }
218
219     DALI_LOG_RELEASE_INFO("receive data, type:%s, data:%s\n", ev->mimetype, content.c_str());
220
221     auto it = mDataRequestIds.begin();
222     while(it != mDataRequestIds.end())
223     {
224       uint32_t dataRequestId = *it;
225       auto     item          = mDataRequestItems.find(dataRequestId);
226       if(item != mDataRequestItems.end())
227       {
228         Ecore_Wl2_Offer* offer = static_cast<Ecore_Wl2_Offer*>(item->second.second);
229         if(offer == ev->offer)
230         {
231           std::string mimeType = static_cast<std::string>(item->second.first);
232           mDataRequestItems.erase(dataRequestId);
233           it = mDataRequestIds.erase(it);
234           DALI_LOG_RELEASE_INFO("receive data, success signal emit, id:%u, type:%s\n", dataRequestId, mimeType.c_str());
235           mDataReceivedSignal.Emit(dataRequestId, mimeType.c_str(), content.c_str());
236         }
237         else
238         {
239           ++it;
240         }
241       }
242     }
243   }
244
245   void SelectionOffer(void* event)
246   {
247     Ecore_Wl2_Event_Seat_Selection *ev = reinterpret_cast<Ecore_Wl2_Event_Seat_Selection*>(event);
248
249     if(ev == nullptr)
250     {
251       DALI_LOG_ERROR("ev is nullptr.\n");
252       return;
253     }
254
255     if(ev->num_types < 1)
256     {
257       DALI_LOG_ERROR("num type is 0.\n");
258       return;
259     }
260
261     if(ev->types == nullptr)
262     {
263       DALI_LOG_ERROR("types is nullptr.\n");
264       return;
265     }
266
267     const char* selectedType = nullptr;
268     std::string formatMarkup("application/x-elementary-markup");
269
270     for(int i = 0; i < ev->num_types; i++)
271     {
272       DALI_LOG_RELEASE_INFO("mime type(%s)", ev->types[i]);
273       if(!formatMarkup.compare(ev->types[i]))
274       {
275         continue;
276       }
277
278       if(!selectedType)
279       {
280         selectedType = ev->types[i];
281       }
282     }
283
284     if(!selectedType)
285     {
286       DALI_LOG_ERROR("mime type is invalid.\n");
287       return;
288     }
289
290     DALI_LOG_RELEASE_INFO("data selected signal emit, type:%s\n", selectedType);
291     mDataSelectedSignal.Emit(selectedType);
292   }
293
294   uint32_t             mSerial{std::numeric_limits<uint32_t>::max()};
295   std::string          mMimeType;
296   std::string          mData;
297   Ecore_Event_Handler* mSendHandler{nullptr};
298   Ecore_Event_Handler* mReceiveHandler{nullptr};
299   Ecore_Event_Handler* mSelectionHanlder{nullptr};
300
301   Dali::Clipboard::DataSentSignalType     mDataSentSignal;
302   Dali::Clipboard::DataReceivedSignalType mDataReceivedSignal;
303   Dali::Clipboard::DataSelectedSignalType mDataSelectedSignal;
304
305   uint32_t mDataId{0};
306   std::vector<uint32_t> mDataRequestIds;
307   std::unordered_map<uint32_t, std::pair<std::string, Ecore_Wl2_Offer*>> mDataRequestItems;
308 };
309
310 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
311 {
312   Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
313   impl->SendData(event);
314
315   return ECORE_CALLBACK_PASS_ON;
316 }
317
318 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
319 {
320   Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
321   impl->ReceiveData(event);
322
323   return ECORE_CALLBACK_PASS_ON;
324 }
325
326 static Eina_Bool EcoreEventSelectionOffer(void* data, int type, void* event)
327 {
328   Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
329   impl->SelectionOffer(event);
330
331   return ECORE_CALLBACK_PASS_ON;
332 }
333
334 Clipboard::Clipboard(Impl* impl)
335 : mImpl(impl)
336 {
337 }
338
339 Clipboard::~Clipboard()
340 {
341   delete mImpl;
342 }
343
344 Dali::Clipboard Clipboard::Get()
345 {
346   Dali::Clipboard clipboard;
347
348   Dali::SingletonService service(SingletonService::Get());
349   if(service)
350   {
351     // Check whether the singleton is already created
352     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
353     if(handle)
354     {
355       // If so, downcast the handle
356       clipboard = Dali::Clipboard(dynamic_cast<Clipboard*>(handle.GetObjectPtr()));
357     }
358     else
359     {
360       Clipboard::Impl* impl(new Clipboard::Impl());
361       clipboard = Dali::Clipboard(new Clipboard(impl));
362       service.Register(typeid(Dali::Clipboard), clipboard);
363     }
364   }
365
366   return clipboard;
367 }
368
369 bool Clipboard::IsAvailable()
370 {
371   Dali::SingletonService service(SingletonService::Get());
372   if(service)
373   {
374     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
375     if(handle)
376     {
377       return true;
378     }
379   }
380   return false;
381 }
382
383 Dali::Clipboard::DataSentSignalType& Clipboard::DataSentSignal()
384 {
385   return mImpl->mDataSentSignal;
386 }
387
388 Dali::Clipboard::DataReceivedSignalType& Clipboard::DataReceivedSignal()
389 {
390   return mImpl->mDataReceivedSignal;
391 }
392
393 Dali::Clipboard::DataSelectedSignalType& Clipboard::DataSelectedSignal()
394 {
395   return mImpl->mDataSelectedSignal;
396 }
397
398 bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
399 {
400   return mImpl->SetData(clipData);
401 }
402
403 uint32_t Clipboard::GetData(const std::string &mimeType)
404 {
405   return mImpl->GetData(mimeType);
406 }
407
408 size_t Clipboard::NumberOfItems()
409 {
410   // TODO: We should to check if the data is empty in the clipboard service.
411   return 1u;
412 }
413
414 void Clipboard::ShowClipboard()
415 {
416 }
417
418 void Clipboard::HideClipboard(bool skipFirstHide)
419 {
420 }
421
422 bool Clipboard::IsVisible() const
423 {
424   return false;
425 }
426
427 bool Clipboard::OnReceiveData()
428 {
429   return false;
430 }
431
432 } // namespace Adaptor
433
434 } // namespace Internal
435
436 } // namespace Dali