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