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>
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);
37 struct Clipboard::Impl
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);
47 ecore_event_handler_del(mSendHandler);
48 ecore_event_handler_del(mReceiveHandler);
49 ecore_event_handler_del(mSelectionHanlder);
52 bool SetData(const Dali::Clipboard::ClipData& clipData)
54 mMimeType = clipData.GetMimeType();
55 mData = clipData.GetData();
59 DALI_LOG_ERROR("ClipData is empty, return false.\n");
63 const char* mimeTypes[2];
64 mimeTypes[0] = mMimeType.c_str();
65 mimeTypes[1] = nullptr;
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());
75 uint32_t GetData(const std::string &mimeType)
77 const char* type = mimeType.c_str();
80 DALI_LOG_ERROR("no request type, type is null.\n");
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);
90 DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
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);
98 for(unsigned int i = 0; i < typeCount && !selectedType; ++i)
100 char* availableType = (char*)eina_array_data_get((Eina_Array *)availableTypes, i);
101 if(!mimeType.compare(availableType))
103 selectedType = availableType;
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)
113 DALI_LOG_ERROR("available type[%u]:%s\n", i, (char*)eina_array_data_get((Eina_Array *)availableTypes, i));
119 mDataRequestIds.push_back(mDataId);
120 mDataRequestItems[mDataId] = std::make_pair(mimeType, offer);
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));
128 void SendData(void* event)
130 Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
132 if(ev->serial != mSerial)
137 // no matching mime type.
138 if(mMimeType.compare(ev->type))
140 auto it = mDataRequestIds.begin();
141 while(it != mDataRequestIds.end())
143 uint32_t dataRequestId = *it;
144 auto item = mDataRequestItems.find(dataRequestId);
145 if(item != mDataRequestItems.end())
147 std::string mimeType = static_cast<std::string>(item->second.first);
148 if(!mimeType.compare(ev->type))
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, "", "");
164 size_t dataLength = strlen(mData.c_str());
165 size_t bufferSize = dataLength + 1u;
167 char* buffer = new char[bufferSize];
173 memcpy(buffer, mData.c_str(), dataLength);
174 buffer[dataLength] = '\0';
176 auto ret = write(ev->fd, buffer, bufferSize);
177 if(DALI_UNLIKELY(ret != static_cast<ssize_t>(bufferSize)))
179 DALI_LOG_ERROR("write(ev->fd) return %zd\n", ret);
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());
189 void ReceiveData(void* event)
191 Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
195 DALI_LOG_ERROR("ev is nullptr.\n");
199 if(ev->data == nullptr || ev->len < 1)
201 DALI_LOG_ERROR("no selection data.\n");
205 size_t dataLength = strlen(ev->data);
206 size_t bufferSize = static_cast<size_t>(ev->len);
209 if(dataLength < bufferSize)
211 content.append(ev->data, dataLength);
215 content.append(ev->data, bufferSize);
218 DALI_LOG_RELEASE_INFO("receive data, type:%s, data:%s\n", ev->mimetype, content.c_str());
220 auto it = mDataRequestIds.begin();
221 while(it != mDataRequestIds.end())
223 uint32_t dataRequestId = *it;
224 auto item = mDataRequestItems.find(dataRequestId);
225 if(item != mDataRequestItems.end())
227 Ecore_Wl2_Offer* offer = static_cast<Ecore_Wl2_Offer*>(item->second.second);
228 if(offer == ev->offer)
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());
244 void SelectionOffer(void* event)
246 Ecore_Wl2_Event_Seat_Selection *ev = reinterpret_cast<Ecore_Wl2_Event_Seat_Selection*>(event);
250 DALI_LOG_ERROR("ev is nullptr.\n");
254 if(ev->num_types < 1)
256 DALI_LOG_ERROR("num type is 0.\n");
260 if(ev->types == nullptr)
262 DALI_LOG_ERROR("types is nullptr.\n");
266 const char* selectedType = nullptr;
267 std::string formatMarkup("application/x-elementary-markup");
269 for(int i = 0; i < ev->num_types; i++)
271 DALI_LOG_RELEASE_INFO("mime type(%s)", ev->types[i]);
272 if(!formatMarkup.compare(ev->types[i]))
279 selectedType = ev->types[i];
285 DALI_LOG_ERROR("mime type is invalid.\n");
289 DALI_LOG_RELEASE_INFO("data selected signal emit, type:%s\n", selectedType);
290 mDataSelectedSignal.Emit(selectedType);
293 uint32_t mSerial{std::numeric_limits<uint32_t>::max()};
294 std::string mMimeType;
296 Ecore_Event_Handler* mSendHandler{nullptr};
297 Ecore_Event_Handler* mReceiveHandler{nullptr};
298 Ecore_Event_Handler* mSelectionHanlder{nullptr};
300 Dali::Clipboard::DataSentSignalType mDataSentSignal;
301 Dali::Clipboard::DataReceivedSignalType mDataReceivedSignal;
302 Dali::Clipboard::DataSelectedSignalType mDataSelectedSignal;
305 std::vector<uint32_t> mDataRequestIds;
306 std::unordered_map<uint32_t, std::pair<std::string, Ecore_Wl2_Offer*>> mDataRequestItems;
309 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
311 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
312 impl->SendData(event);
314 return ECORE_CALLBACK_PASS_ON;
317 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
319 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
320 impl->ReceiveData(event);
322 return ECORE_CALLBACK_PASS_ON;
325 static Eina_Bool EcoreEventSelectionOffer(void* data, int type, void* event)
327 Clipboard::Impl* impl = reinterpret_cast<Clipboard::Impl*>(data);
328 impl->SelectionOffer(event);
330 return ECORE_CALLBACK_PASS_ON;
333 Clipboard::Clipboard(Impl* impl)
338 Clipboard::~Clipboard()
343 Dali::Clipboard Clipboard::Get()
345 Dali::Clipboard clipboard;
347 Dali::SingletonService service(SingletonService::Get());
350 // Check whether the singleton is already created
351 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
354 // If so, downcast the handle
355 clipboard = Dali::Clipboard(dynamic_cast<Clipboard*>(handle.GetObjectPtr()));
359 Clipboard::Impl* impl(new Clipboard::Impl());
360 clipboard = Dali::Clipboard(new Clipboard(impl));
361 service.Register(typeid(Dali::Clipboard), clipboard);
368 bool Clipboard::IsAvailable()
370 Dali::SingletonService service(SingletonService::Get());
373 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::Clipboard));
382 Dali::Clipboard::DataSentSignalType& Clipboard::DataSentSignal()
384 return mImpl->mDataSentSignal;
387 Dali::Clipboard::DataReceivedSignalType& Clipboard::DataReceivedSignal()
389 return mImpl->mDataReceivedSignal;
392 Dali::Clipboard::DataSelectedSignalType& Clipboard::DataSelectedSignal()
394 return mImpl->mDataSelectedSignal;
397 bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
399 return mImpl->SetData(clipData);
402 uint32_t Clipboard::GetData(const std::string &mimeType)
404 return mImpl->GetData(mimeType);
407 size_t Clipboard::NumberOfItems()
409 // TODO: We should to check if the data is empty in the clipboard service.
413 void Clipboard::ShowClipboard()
417 void Clipboard::HideClipboard(bool skipFirstHide)
421 bool Clipboard::IsVisible() const
426 bool Clipboard::OnReceiveData()
431 } // namespace Adaptor
433 } // namespace Internal