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