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 HasType(const std::string& mimeType)
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);
61 DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
65 Eina_Array* availableTypes = ecore_wl2_offer_mimes_get(offer);
66 unsigned int typeCount = (unsigned int)eina_array_count((Eina_Array *)availableTypes);
68 for(unsigned int i = 0; i < typeCount; ++i)
70 char* availableType = (char*)eina_array_data_get((Eina_Array *)availableTypes, i);
71 if(!mimeType.compare(availableType))
79 bool SetData(const Dali::Clipboard::ClipData& clipData)
81 mMimeType = clipData.GetMimeType();
82 mData = clipData.GetData();
86 DALI_LOG_ERROR("ClipData is empty, return false.\n");
90 const char* mimeTypes[2];
91 mimeTypes[0] = mMimeType.c_str();
92 mimeTypes[1] = nullptr;
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());
102 uint32_t GetData(const std::string &mimeType)
104 const char* type = mimeType.c_str();
107 DALI_LOG_ERROR("no request type, type is null.\n");
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);
117 DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
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);
125 for(unsigned int i = 0; i < typeCount && !selectedType; ++i)
127 char* availableType = (char*)eina_array_data_get((Eina_Array *)availableTypes, i);
128 if(!mimeType.compare(availableType))
130 selectedType = availableType;
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)
140 DALI_LOG_ERROR("available type[%u]:%s\n", i, (char*)eina_array_data_get((Eina_Array *)availableTypes, i));
146 mDataRequestIds.push_back(mDataId);
147 mDataRequestItems[mDataId] = std::make_pair(mimeType, offer);
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));
155 void SendData(void* event)
157 Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
159 if(ev->serial != mSerial)
164 // no matching mime type.
165 if(mMimeType.compare(ev->type))
167 auto it = mDataRequestIds.begin();
168 while(it != mDataRequestIds.end())
170 uint32_t dataRequestId = *it;
171 auto item = mDataRequestItems.find(dataRequestId);
172 if(item != mDataRequestItems.end())
174 std::string mimeType = static_cast<std::string>(item->second.first);
175 if(!mimeType.compare(ev->type))
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, "", "");
191 size_t dataLength = strlen(mData.c_str());
192 size_t bufferSize = dataLength + 1u;
194 char* buffer = new char[bufferSize];
200 memcpy(buffer, mData.c_str(), dataLength);
201 buffer[dataLength] = '\0';
203 auto ret = write(ev->fd, buffer, bufferSize);
204 if(DALI_UNLIKELY(ret != static_cast<ssize_t>(bufferSize)))
206 DALI_LOG_ERROR("write(ev->fd) return %zd\n", ret);
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());
216 void ReceiveData(void* event)
218 Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
222 DALI_LOG_ERROR("ev is nullptr.\n");
226 if(ev->data == nullptr || ev->len < 1)
228 DALI_LOG_ERROR("no selection data.\n");
232 size_t dataLength = strlen(ev->data);
233 size_t bufferSize = static_cast<size_t>(ev->len);
236 if(dataLength < bufferSize)
238 content.append(ev->data, dataLength);
242 content.append(ev->data, bufferSize);
245 DALI_LOG_RELEASE_INFO("receive data, type:%s, data:%s\n", ev->mimetype, content.c_str());
247 auto it = mDataRequestIds.begin();
248 while(it != mDataRequestIds.end())
250 uint32_t dataRequestId = *it;
251 auto item = mDataRequestItems.find(dataRequestId);
252 if(item != mDataRequestItems.end())
254 Ecore_Wl2_Offer* offer = static_cast<Ecore_Wl2_Offer*>(item->second.second);
255 if(offer == ev->offer)
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());
271 void SelectionOffer(void* event)
273 Ecore_Wl2_Event_Seat_Selection *ev = reinterpret_cast<Ecore_Wl2_Event_Seat_Selection*>(event);
277 DALI_LOG_ERROR("ev is nullptr.\n");
281 if(ev->num_types < 1)
283 DALI_LOG_ERROR("num type is 0.\n");
287 if(ev->types == nullptr)
289 DALI_LOG_ERROR("types is nullptr.\n");
293 const char* selectedType = nullptr;
294 std::string formatMarkup("application/x-elementary-markup");
296 for(int i = 0; i < ev->num_types; i++)
298 DALI_LOG_RELEASE_INFO("mime type(%s)", ev->types[i]);
299 if(!formatMarkup.compare(ev->types[i]))
306 selectedType = ev->types[i];
312 DALI_LOG_ERROR("mime type is invalid.\n");
316 DALI_LOG_RELEASE_INFO("data selected signal emit, type:%s\n", selectedType);
317 mDataSelectedSignal.Emit(selectedType);
320 uint32_t mSerial{std::numeric_limits<uint32_t>::max()};
321 std::string mMimeType;
323 Ecore_Event_Handler* mSendHandler{nullptr};
324 Ecore_Event_Handler* mReceiveHandler{nullptr};
325 Ecore_Event_Handler* mSelectionHanlder{nullptr};
327 Dali::Clipboard::DataSentSignalType mDataSentSignal;
328 Dali::Clipboard::DataReceivedSignalType mDataReceivedSignal;
329 Dali::Clipboard::DataSelectedSignalType mDataSelectedSignal;
332 std::vector<uint32_t> mDataRequestIds;
333 std::unordered_map<uint32_t, std::pair<std::string, Ecore_Wl2_Offer*>> mDataRequestItems;
336 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
338 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
339 impl->SendData(event);
341 return ECORE_CALLBACK_PASS_ON;
344 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
346 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
347 impl->ReceiveData(event);
349 return ECORE_CALLBACK_PASS_ON;
352 static Eina_Bool EcoreEventSelectionOffer(void* data, int type, void* event)
354 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
355 impl->SelectionOffer(event);
357 return ECORE_CALLBACK_PASS_ON;
360 Clipboard::Clipboard(Impl* impl)
365 Clipboard::~Clipboard()
370 Dali::Clipboard Clipboard::Get()
372 Dali::Clipboard clipboard;
374 Dali::SingletonService service(SingletonService::Get());
377 // Check whether the singleton is already created
378 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
381 // If so, downcast the handle
382 clipboard = Dali::Clipboard(dynamic_cast<Clipboard*>(handle.GetObjectPtr()));
386 Clipboard::Impl* impl(new Clipboard::Impl());
387 clipboard = Dali::Clipboard(new Clipboard(impl));
388 service.Register(typeid(Dali::Clipboard), clipboard);
395 bool Clipboard::IsAvailable()
397 Dali::SingletonService service(SingletonService::Get());
400 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
409 Dali::Clipboard::DataSentSignalType& Clipboard::DataSentSignal()
411 return mImpl->mDataSentSignal;
414 Dali::Clipboard::DataReceivedSignalType& Clipboard::DataReceivedSignal()
416 return mImpl->mDataReceivedSignal;
419 Dali::Clipboard::DataSelectedSignalType& Clipboard::DataSelectedSignal()
421 return mImpl->mDataSelectedSignal;
424 bool Clipboard::HasType(const std::string& mimeType)
426 return mImpl->HasType(mimeType);
429 bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
431 return mImpl->SetData(clipData);
434 uint32_t Clipboard::GetData(const std::string &mimeType)
436 return mImpl->GetData(mimeType);
439 size_t Clipboard::NumberOfItems()
441 bool isItem = HasType(MIME_TYPE_TEXT_PLAIN) || HasType(MIME_TYPE_HTML) || HasType(MIME_TYPE_TEXT_URI);
442 return isItem ? 1u : 0u;
445 void Clipboard::ShowClipboard()
449 void Clipboard::HideClipboard(bool skipFirstHide)
453 bool Clipboard::IsVisible() const
458 bool Clipboard::OnReceiveData()
463 } // namespace Adaptor
465 } // namespace Internal