2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/clipboard/common/clipboard-impl.h>
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>
26 #include <unordered_map>
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);
38 struct Clipboard::Impl
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);
48 ecore_event_handler_del(mSendHandler);
49 ecore_event_handler_del(mReceiveHandler);
50 ecore_event_handler_del(mSelectionHanlder);
53 bool SetData(const Dali::Clipboard::ClipData& clipData)
55 mMimeType = clipData.GetMimeType();
56 mData = clipData.GetData();
60 DALI_LOG_ERROR("ClipData is empty, return false.\n");
64 const char* mimeTypes[2];
65 mimeTypes[0] = mMimeType.c_str();
66 mimeTypes[1] = nullptr;
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());
76 uint32_t GetData(const std::string &mimeType)
78 const char* type = mimeType.c_str();
81 DALI_LOG_ERROR("no request type, type is null.\n");
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);
91 DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
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);
99 for(unsigned int i = 0; i < typeCount && !selectedType; ++i)
101 char* availableType = (char*)eina_array_data_get((Eina_Array *)availableTypes, i);
102 if(!mimeType.compare(availableType))
104 selectedType = availableType;
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)
114 DALI_LOG_ERROR("available type[%u]:%s\n", i, (char*)eina_array_data_get((Eina_Array *)availableTypes, i));
120 mDataRequestIds.push_back(mDataId);
121 mDataRequestItems[mDataId] = std::make_pair(mimeType, offer);
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));
129 void SendData(void* event)
131 Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
133 if(ev->serial != mSerial)
138 // no matching mime type.
139 if(mMimeType.compare(ev->type))
141 auto it = mDataRequestIds.begin();
142 while(it != mDataRequestIds.end())
144 uint32_t dataRequestId = *it;
145 auto item = mDataRequestItems.find(dataRequestId);
146 if(item != mDataRequestItems.end())
148 std::string mimeType = static_cast<std::string>(item->second.first);
149 if(!mimeType.compare(ev->type))
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, "", "");
165 size_t dataLength = strlen(mData.c_str());
166 size_t bufferSize = dataLength + 1u;
168 char* buffer = new char[bufferSize];
174 memcpy(buffer, mData.c_str(), dataLength);
175 buffer[dataLength] = '\0';
177 auto ret = write(ev->fd, buffer, bufferSize);
178 if(DALI_UNLIKELY(ret != static_cast<ssize_t>(bufferSize)))
180 DALI_LOG_ERROR("write(ev->fd) return %zd\n", ret);
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());
190 void ReceiveData(void* event)
192 Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
196 DALI_LOG_ERROR("ev is nullptr.\n");
200 if(ev->data == nullptr || ev->len < 1)
202 DALI_LOG_ERROR("no selection data.\n");
206 size_t dataLength = strlen(ev->data);
207 size_t bufferSize = static_cast<size_t>(ev->len);
210 if(dataLength < bufferSize)
212 content.append(ev->data, dataLength);
216 content.append(ev->data, bufferSize);
219 DALI_LOG_RELEASE_INFO("receive data, type:%s, data:%s\n", ev->mimetype, content.c_str());
221 auto it = mDataRequestIds.begin();
222 while(it != mDataRequestIds.end())
224 uint32_t dataRequestId = *it;
225 auto item = mDataRequestItems.find(dataRequestId);
226 if(item != mDataRequestItems.end())
228 Ecore_Wl2_Offer* offer = static_cast<Ecore_Wl2_Offer*>(item->second.second);
229 if(offer == ev->offer)
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());
245 void SelectionOffer(void* event)
247 Ecore_Wl2_Event_Seat_Selection *ev = reinterpret_cast<Ecore_Wl2_Event_Seat_Selection*>(event);
251 DALI_LOG_ERROR("ev is nullptr.\n");
255 if(ev->num_types < 1)
257 DALI_LOG_ERROR("num type is 0.\n");
261 if(ev->types == nullptr)
263 DALI_LOG_ERROR("types is nullptr.\n");
267 const char* selectedType = nullptr;
268 std::string formatMarkup("application/x-elementary-markup");
270 for(int i = 0; i < ev->num_types; i++)
272 DALI_LOG_RELEASE_INFO("mime type(%s)", ev->types[i]);
273 if(!formatMarkup.compare(ev->types[i]))
280 selectedType = ev->types[i];
286 DALI_LOG_ERROR("mime type is invalid.\n");
290 DALI_LOG_RELEASE_INFO("data selected signal emit, type:%s\n", selectedType);
291 mDataSelectedSignal.Emit(selectedType);
294 uint32_t mSerial{std::numeric_limits<uint32_t>::max()};
295 std::string mMimeType;
297 Ecore_Event_Handler* mSendHandler{nullptr};
298 Ecore_Event_Handler* mReceiveHandler{nullptr};
299 Ecore_Event_Handler* mSelectionHanlder{nullptr};
301 Dali::Clipboard::DataSentSignalType mDataSentSignal;
302 Dali::Clipboard::DataReceivedSignalType mDataReceivedSignal;
303 Dali::Clipboard::DataSelectedSignalType mDataSelectedSignal;
306 std::vector<uint32_t> mDataRequestIds;
307 std::unordered_map<uint32_t, std::pair<std::string, Ecore_Wl2_Offer*>> mDataRequestItems;
310 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
312 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
313 impl->SendData(event);
315 return ECORE_CALLBACK_PASS_ON;
318 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
320 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
321 impl->ReceiveData(event);
323 return ECORE_CALLBACK_PASS_ON;
326 static Eina_Bool EcoreEventSelectionOffer(void* data, int type, void* event)
328 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
329 impl->SelectionOffer(event);
331 return ECORE_CALLBACK_PASS_ON;
334 Clipboard::Clipboard(Impl* impl)
339 Clipboard::~Clipboard()
344 Dali::Clipboard Clipboard::Get()
346 Dali::Clipboard clipboard;
348 Dali::SingletonService service(SingletonService::Get());
351 // Check whether the singleton is already created
352 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
355 // If so, downcast the handle
356 clipboard = Dali::Clipboard(dynamic_cast<Clipboard*>(handle.GetObjectPtr()));
360 Clipboard::Impl* impl(new Clipboard::Impl());
361 clipboard = Dali::Clipboard(new Clipboard(impl));
362 service.Register(typeid(Dali::Clipboard), clipboard);
369 bool Clipboard::IsAvailable()
371 Dali::SingletonService service(SingletonService::Get());
374 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
383 Dali::Clipboard::DataSentSignalType& Clipboard::DataSentSignal()
385 return mImpl->mDataSentSignal;
388 Dali::Clipboard::DataReceivedSignalType& Clipboard::DataReceivedSignal()
390 return mImpl->mDataReceivedSignal;
393 Dali::Clipboard::DataSelectedSignalType& Clipboard::DataSelectedSignal()
395 return mImpl->mDataSelectedSignal;
398 bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
400 return mImpl->SetData(clipData);
403 uint32_t Clipboard::GetData(const std::string &mimeType)
405 return mImpl->GetData(mimeType);
408 size_t Clipboard::NumberOfItems()
410 // TODO: We should to check if the data is empty in the clipboard service.
414 void Clipboard::ShowClipboard()
418 void Clipboard::HideClipboard(bool skipFirstHide)
422 bool Clipboard::IsVisible() const
427 bool Clipboard::OnReceiveData()
432 } // namespace Adaptor
434 } // namespace Internal