[dali_2.3.24] Merge branch 'devel/master'
[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 HasType(const std::string& mimeType)
54   {
55     Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
56     Ecore_Wl2_Input*   input   = ecore_wl2_input_default_input_get(display);
57     Ecore_Wl2_Offer*   offer   = ecore_wl2_dnd_selection_get(input);
58
59     if(!offer)
60     {
61       DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
62       return false;
63     }
64
65     Eina_Array*  availableTypes = ecore_wl2_offer_mimes_get(offer);
66     unsigned int typeCount      = (unsigned int)eina_array_count((Eina_Array *)availableTypes);
67
68     for(unsigned int i = 0; i < typeCount; ++i)
69     {
70       char* availableType = (char*)eina_array_data_get((Eina_Array *)availableTypes, i);
71       if(!mimeType.compare(availableType))
72       {
73         return true;
74       }
75     }
76     return false;
77   }
78
79   bool SetData(const Dali::Clipboard::ClipData& clipData)
80   {
81     mMimeType = clipData.GetMimeType();
82     mData     = clipData.GetData();
83
84     if(mData.empty())
85     {
86       DALI_LOG_ERROR("ClipData is empty, return false.\n");
87       return false;
88     }
89
90     const char* mimeTypes[2];
91     mimeTypes[0] = mMimeType.c_str();
92     mimeTypes[1] = nullptr;
93
94     Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
95     Ecore_Wl2_Input* input     = ecore_wl2_input_default_input_get(display);
96     mSerial                    = ecore_wl2_dnd_selection_set(input, mimeTypes);
97     DALI_LOG_RELEASE_INFO("selection_set success, serial:%u, type:%s, data:%s\n", mSerial, mMimeType.c_str(), mData.c_str());
98
99     return true;
100   }
101
102   uint32_t GetData(const std::string &mimeType)
103   {
104     const char* type = mimeType.c_str();
105     if(!type)
106     {
107       DALI_LOG_ERROR("no request type, type is null.\n");
108       return 0u;
109     }
110
111     Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
112     Ecore_Wl2_Input*   input   = ecore_wl2_input_default_input_get(display);
113     Ecore_Wl2_Offer*   offer   = ecore_wl2_dnd_selection_get(input);
114
115     if(!offer)
116     {
117       DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
118       return 0u;
119     }
120
121     Eina_Array*  availableTypes = ecore_wl2_offer_mimes_get(offer);
122     char*        selectedType   = nullptr;
123     unsigned int typeCount      = (unsigned int)eina_array_count((Eina_Array *)availableTypes);
124
125     for(unsigned int i = 0; i < typeCount && !selectedType; ++i)
126     {
127       char* availableType = (char*)eina_array_data_get((Eina_Array *)availableTypes, i);
128       if(!mimeType.compare(availableType))
129       {
130         selectedType = availableType;
131         break;
132       }
133     }
134
135     if(!selectedType)
136     {
137       DALI_LOG_ERROR("no matching type, num of available types:%u, request type:%s\n", typeCount, mimeType.c_str());
138       for(unsigned int i = 0; i < typeCount && !selectedType; ++i)
139       {
140         DALI_LOG_ERROR("available type[%u]:%s\n", i, (char*)eina_array_data_get((Eina_Array *)availableTypes, i));
141       }
142       return 0u;
143     }
144
145     mDataId++;
146     mDataRequestIds.push_back(mDataId);
147     mDataRequestItems[mDataId] = std::make_pair(mimeType, offer);
148
149     DALI_LOG_RELEASE_INFO("offer_receive, id:%u, request type:%s\n", mDataId, mimeType.c_str());
150     ecore_wl2_offer_receive(offer, const_cast<char*>(type));
151     ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
152     return mDataId;
153   }
154
155   void SendData(void* event)
156   {
157     Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
158
159     if(ev->serial != mSerial)
160     {
161       return;
162     }
163
164     // no matching mime type.
165     if(mMimeType.compare(ev->type))
166     {
167       auto it = mDataRequestIds.begin();
168       while(it != mDataRequestIds.end())
169       {
170         uint32_t dataRequestId = *it;
171         auto     item          = mDataRequestItems.find(dataRequestId);
172         if(item != mDataRequestItems.end())
173         {
174           std::string mimeType = static_cast<std::string>(item->second.first);
175           if(!mimeType.compare(ev->type))
176           {
177             mDataRequestItems.erase(dataRequestId);
178             it = mDataRequestIds.erase(it);
179             DALI_LOG_ERROR("no matching type, empty signal emit, request type:%s, available type:%s\n", ev->type, mMimeType.c_str());
180             mDataReceivedSignal.Emit(dataRequestId, "", "");
181           }
182           else
183           {
184             ++it;
185           }
186         }
187       }
188       return;
189     }
190
191     size_t dataLength = strlen(mData.c_str());
192     size_t bufferSize = dataLength + 1u;
193
194     char* buffer = new char[bufferSize];
195     if(!buffer)
196     {
197       return;
198     }
199
200     memcpy(buffer, mData.c_str(), dataLength);
201     buffer[dataLength] = '\0';
202
203     auto ret = write(ev->fd, buffer, bufferSize);
204     if(DALI_UNLIKELY(ret != static_cast<ssize_t>(bufferSize)))
205     {
206       DALI_LOG_ERROR("write(ev->fd) return %zd\n", ret);
207     }
208
209     close(ev->fd);
210     delete[] buffer;
211
212     DALI_LOG_RELEASE_INFO("send data, type:%s, data:%s \n", mMimeType.c_str(), mData.c_str());
213     mDataSentSignal.Emit(ev->type, mData.c_str());
214   }
215
216   void ReceiveData(void* event)
217   {
218     Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
219
220     if(ev == nullptr)
221     {
222       DALI_LOG_ERROR("ev is nullptr.\n");
223       return;
224     }
225
226     if(ev->data == nullptr || ev->len < 1)
227     {
228       DALI_LOG_ERROR("no selection data.\n");
229       return;
230     }
231
232     size_t      dataLength = strlen(ev->data);
233     size_t      bufferSize = static_cast<size_t>(ev->len);
234     std::string content;
235
236     if(dataLength < bufferSize)
237     {
238       content.append(ev->data, dataLength);
239     }
240     else
241     {
242       content.append(ev->data, bufferSize);
243     }
244
245     DALI_LOG_RELEASE_INFO("receive data, type:%s, data:%s\n", ev->mimetype, content.c_str());
246
247     auto it = mDataRequestIds.begin();
248     while(it != mDataRequestIds.end())
249     {
250       uint32_t dataRequestId = *it;
251       auto     item          = mDataRequestItems.find(dataRequestId);
252       if(item != mDataRequestItems.end())
253       {
254         Ecore_Wl2_Offer* offer = static_cast<Ecore_Wl2_Offer*>(item->second.second);
255         if(offer == ev->offer)
256         {
257           std::string mimeType = static_cast<std::string>(item->second.first);
258           mDataRequestItems.erase(dataRequestId);
259           it = mDataRequestIds.erase(it);
260           DALI_LOG_RELEASE_INFO("receive data, success signal emit, id:%u, type:%s\n", dataRequestId, mimeType.c_str());
261           mDataReceivedSignal.Emit(dataRequestId, mimeType.c_str(), content.c_str());
262         }
263         else
264         {
265           ++it;
266         }
267       }
268     }
269   }
270
271   void SelectionOffer(void* event)
272   {
273     Ecore_Wl2_Event_Seat_Selection *ev = reinterpret_cast<Ecore_Wl2_Event_Seat_Selection*>(event);
274
275     if(ev == nullptr)
276     {
277       DALI_LOG_ERROR("ev is nullptr.\n");
278       return;
279     }
280
281     if(ev->num_types < 1)
282     {
283       DALI_LOG_ERROR("num type is 0.\n");
284       return;
285     }
286
287     if(ev->types == nullptr)
288     {
289       DALI_LOG_ERROR("types is nullptr.\n");
290       return;
291     }
292
293     const char* selectedType = nullptr;
294     std::string formatMarkup("application/x-elementary-markup");
295
296     for(int i = 0; i < ev->num_types; i++)
297     {
298       DALI_LOG_RELEASE_INFO("mime type(%s)", ev->types[i]);
299       if(!formatMarkup.compare(ev->types[i]))
300       {
301         continue;
302       }
303
304       if(!selectedType)
305       {
306         selectedType = ev->types[i];
307       }
308     }
309
310     if(!selectedType)
311     {
312       DALI_LOG_ERROR("mime type is invalid.\n");
313       return;
314     }
315
316     DALI_LOG_RELEASE_INFO("data selected signal emit, type:%s\n", selectedType);
317     mDataSelectedSignal.Emit(selectedType);
318   }
319
320   uint32_t             mSerial{std::numeric_limits<uint32_t>::max()};
321   std::string          mMimeType;
322   std::string          mData;
323   Ecore_Event_Handler* mSendHandler{nullptr};
324   Ecore_Event_Handler* mReceiveHandler{nullptr};
325   Ecore_Event_Handler* mSelectionHanlder{nullptr};
326
327   Dali::Clipboard::DataSentSignalType     mDataSentSignal;
328   Dali::Clipboard::DataReceivedSignalType mDataReceivedSignal;
329   Dali::Clipboard::DataSelectedSignalType mDataSelectedSignal;
330
331   uint32_t mDataId{0};
332   std::vector<uint32_t> mDataRequestIds;
333   std::unordered_map<uint32_t, std::pair<std::string, Ecore_Wl2_Offer*>> mDataRequestItems;
334 };
335
336 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
337 {
338   Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
339   impl->SendData(event);
340
341   return ECORE_CALLBACK_PASS_ON;
342 }
343
344 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
345 {
346   Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
347   impl->ReceiveData(event);
348
349   return ECORE_CALLBACK_PASS_ON;
350 }
351
352 static Eina_Bool EcoreEventSelectionOffer(void* data, int type, void* event)
353 {
354   Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
355   impl->SelectionOffer(event);
356
357   return ECORE_CALLBACK_PASS_ON;
358 }
359
360 Clipboard::Clipboard(Impl* impl)
361 : mImpl(impl)
362 {
363 }
364
365 Clipboard::~Clipboard()
366 {
367   delete mImpl;
368 }
369
370 Dali::Clipboard Clipboard::Get()
371 {
372   Dali::Clipboard clipboard;
373
374   Dali::SingletonService service(SingletonService::Get());
375   if(service)
376   {
377     // Check whether the singleton is already created
378     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
379     if(handle)
380     {
381       // If so, downcast the handle
382       clipboard = Dali::Clipboard(dynamic_cast<Clipboard*>(handle.GetObjectPtr()));
383     }
384     else
385     {
386       Clipboard::Impl* impl(new Clipboard::Impl());
387       clipboard = Dali::Clipboard(new Clipboard(impl));
388       service.Register(typeid(Dali::Clipboard), clipboard);
389     }
390   }
391
392   return clipboard;
393 }
394
395 bool Clipboard::IsAvailable()
396 {
397   Dali::SingletonService service(SingletonService::Get());
398   if(service)
399   {
400     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
401     if(handle)
402     {
403       return true;
404     }
405   }
406   return false;
407 }
408
409 Dali::Clipboard::DataSentSignalType& Clipboard::DataSentSignal()
410 {
411   return mImpl->mDataSentSignal;
412 }
413
414 Dali::Clipboard::DataReceivedSignalType& Clipboard::DataReceivedSignal()
415 {
416   return mImpl->mDataReceivedSignal;
417 }
418
419 Dali::Clipboard::DataSelectedSignalType& Clipboard::DataSelectedSignal()
420 {
421   return mImpl->mDataSelectedSignal;
422 }
423
424 bool Clipboard::HasType(const std::string& mimeType)
425 {
426   return mImpl->HasType(mimeType);
427 }
428
429 bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
430 {
431   return mImpl->SetData(clipData);
432 }
433
434 uint32_t Clipboard::GetData(const std::string &mimeType)
435 {
436   return mImpl->GetData(mimeType);
437 }
438
439 size_t Clipboard::NumberOfItems()
440 {
441   bool isItem = HasType(MIME_TYPE_TEXT_PLAIN) || HasType(MIME_TYPE_HTML) || HasType(MIME_TYPE_TEXT_URI);
442   return isItem ? 1u : 0u;
443 }
444
445 void Clipboard::ShowClipboard()
446 {
447 }
448
449 void Clipboard::HideClipboard(bool skipFirstHide)
450 {
451 }
452
453 bool Clipboard::IsVisible() const
454 {
455   return false;
456 }
457
458 bool Clipboard::OnReceiveData()
459 {
460   return false;
461 }
462
463 } // namespace Adaptor
464
465 } // namespace Internal
466
467 } // namespace Dali