2 * Copyright (c) 2022 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/drag-and-drop/tizen-wayland/drag-and-drop-impl-ecore-wl2.h>
22 #include <dali/devel-api/common/singleton-service.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h>
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////////////////////////////////////
39 static constexpr int32_t DEFAULT_POSITION = -1;
42 static bool IsIntersection(int px, int py, int tx, int ty, int tw, int th)
44 if(px > tx && py > ty && px < (tx + tw) && py < (ty + th))
51 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
53 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
54 dndImpl->SendData(event);
56 return ECORE_CALLBACK_PASS_ON;
59 static Eina_Bool EcoreEventDataSourceEnd(void* data, int type, void* event)
61 Ecore_Wl2_Event_Data_Source_End *ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_End*>(event);
62 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
65 dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::CANCEL);
69 dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::ACCEPT);
72 return ECORE_CALLBACK_PASS_ON;
75 static Eina_Bool EcoreEventDataSourceDrop(void* data, int type, void* event)
77 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
78 dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::FINISH);
79 return ECORE_CALLBACK_PASS_ON;
82 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
84 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
85 dndImpl->ReceiveData(event);
87 return ECORE_CALLBACK_PASS_ON;
90 static Eina_Bool EcoreEventDataMotion(void* data, int type, void* event)
92 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
93 dndImpl->CalculateDragEvent(event);
95 return ECORE_CALLBACK_PASS_ON;
98 static Eina_Bool EcoreEventDataDrop(void* data, int type, void* event)
100 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
101 dndImpl->CalculateViewRegion(event);
103 return ECORE_CALLBACK_PASS_ON;
106 static Eina_Bool EcoreEventDataEnter(void* data, int type, void* event)
108 Ecore_Wl2_Event_Dnd_Enter* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Enter*>(event);
110 // Set default offer is reject
111 ecore_wl2_offer_accept(ev->offer, NULL);
112 return ECORE_CALLBACK_PASS_ON;
115 static Eina_Bool EcoreEventDataLeave(void* data, int type, void* event)
117 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
118 dndImpl->ResetDropTargets();
120 return ECORE_CALLBACK_PASS_ON;
123 Dali::DragAndDrop GetDragAndDrop()
125 Dali::DragAndDrop dnd;
127 Dali::SingletonService service(SingletonService::Get());
130 // Check whether the singleton is already created
131 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::DragAndDrop));
134 // If so, downcast the handle
135 dnd = Dali::DragAndDrop(dynamic_cast<DragAndDrop*>(handle.GetObjectPtr()));
139 // Create a singleon instance
140 DragAndDropEcoreWl* dndImpl = new DragAndDropEcoreWl();
142 dnd = Dali::DragAndDrop(dndImpl);
143 service.Register(typeid(Dali::DragAndDrop), dnd);
150 DragAndDropEcoreWl::DragAndDropEcoreWl()
153 mSendHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, this);
154 mSourceEndHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_END, EcoreEventDataSourceEnd, this);
155 mSourceDropHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_DROP, EcoreEventDataSourceDrop, this);
158 mReceiveHandler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, EcoreEventOfferDataReady, this);
159 mMotionHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, EcoreEventDataMotion, this);
160 mDropHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, EcoreEventDataDrop, this);
161 mEnterHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_ENTER, EcoreEventDataEnter, this);
162 mLeaveHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_LEAVE, EcoreEventDataLeave, this);
165 DragAndDropEcoreWl::~DragAndDropEcoreWl()
168 ecore_event_handler_del(mSendHandler);
169 ecore_event_handler_del(mSourceEndHandler);
170 ecore_event_handler_del(mSourceDropHandler);
173 ecore_event_handler_del(mReceiveHandler);
174 ecore_event_handler_del(mMotionHandler);
175 ecore_event_handler_del(mDropHandler);
176 ecore_event_handler_del(mEnterHandler);
179 bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const Dali::DragAndDrop::DragData& data, Dali::DragAndDrop::SourceFunction callback)
182 auto parent = Dali::DevelWindow::Get(source);
184 // Set Drag Source Data
185 mMimeType = data.GetMimeType();
186 mData = data.GetData();
189 mSourceCallback = callback;
192 mDragWindow = shadowWindow;
194 // Start Drag and Drop
195 Ecore_Wl2_Window* parentWindow = AnyCast<Ecore_Wl2_Window*>(parent.GetNativeHandle());
196 Ecore_Wl2_Window* dragWindow = AnyCast<Ecore_Wl2_Window*>(mDragWindow.GetNativeHandle());
197 Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
198 Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
200 // Disable Default Cursor
201 ecore_wl2_input_pointer_set(input, NULL, 0, 0);
203 // Set mime type for drag and drop
204 const char* mimeTypes[2];
205 mimeTypes[0] = mMimeType.c_str();
209 ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
211 // Start wayland drag and drop
212 mSerial = ecore_wl2_dnd_drag_start(input, parentWindow, dragWindow);
215 CallSourceEvent(Dali::DragAndDrop::SourceEventType::START);
220 bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback)
222 std::vector<DropTarget>::iterator itr;
223 for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
225 if((*itr).target == target)
231 DropTarget targetData;
232 targetData.target = target;
233 targetData.callback = callback;
234 targetData.inside = false;
236 mDropTargets.push_back(targetData);
241 bool DragAndDropEcoreWl::RemoveListener(Dali::Actor target)
243 std::vector<DropTarget>::iterator itr;
244 for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
246 if((*itr).target == target)
248 mDropTargets.erase(itr);
256 void DragAndDropEcoreWl::CallSourceEvent(Dali::DragAndDrop::SourceEventType type)
260 mSourceCallback(type);
264 void DragAndDropEcoreWl::ResetDropTargets()
266 for(std::size_t i = 0; i < mDropTargets.size(); i++)
268 if(mDropTargets[i].inside)
270 Dali::DragAndDrop::DragEvent dragEvent;
271 dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
272 Dali::Vector2 position(DEFAULT_POSITION, DEFAULT_POSITION);
273 dragEvent.SetPosition(position);
274 mDropTargets[i].callback(dragEvent);
276 mDropTargets[i].inside = false;
281 void DragAndDropEcoreWl::SendData(void* event)
283 Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
284 if(ev->serial != mSerial)
289 int dataLength = strlen(mData.c_str());
290 int bufferSize = dataLength;
291 if((mMimeType.find("text") != std::string::npos) ||
292 (mMimeType.find("markup") != std::string::npos) ||
293 (mMimeType.find("image") != std::string::npos))
298 char* buffer = new char[bufferSize];
304 memcpy(buffer, mData.c_str(), dataLength);
305 buffer[dataLength] = '\0';
307 auto ret = write(ev->fd, buffer, bufferSize);
308 if(DALI_UNLIKELY(ret != bufferSize))
310 DALI_LOG_ERROR("write(ev->fd) return %d! Pleacse check it\n", static_cast<int>(ret));
323 void DragAndDropEcoreWl::ReceiveData(void* event)
325 Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
327 if(mTargetIndex != -1)
329 Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->mimetype, ev->data);
330 mDropTargets[mTargetIndex].callback(dragEvent);
331 mDropTargets[mTargetIndex].inside = false;
332 ecore_wl2_offer_finish(ev->offer);
337 bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
339 Ecore_Wl2_Event_Dnd_Motion* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Motion*>(event);
341 Dali::DragAndDrop::DragEvent dragEvent;
342 Dali::Vector2 curPosition(ev->x, ev->y);
344 for(std::size_t i = 0; i < mDropTargets.size(); i++)
346 Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
347 Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
348 bool currentInside = IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height);
350 // Calculate Drag Enter, Leave, Move Event
351 if(currentInside && !mDropTargets[i].inside)
353 mDropTargets[i].inside = true;
355 dragEvent.SetAction(Dali::DragAndDrop::DragType::ENTER);
356 dragEvent.SetPosition(curPosition);
357 mDropTargets[i].callback(dragEvent);
359 ecore_wl2_offer_mimes_set(ev->offer, ecore_wl2_offer_mimes_get(ev->offer));
361 else if(!currentInside && mDropTargets[i].inside)
363 mDropTargets[i].inside = false;
365 dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
366 dragEvent.SetPosition(curPosition);
367 mDropTargets[i].callback(dragEvent);
369 ecore_wl2_offer_accept(ev->offer, NULL);
371 else if(currentInside && mDropTargets[i].inside)
374 dragEvent.SetAction(Dali::DragAndDrop::DragType::MOVE);
375 dragEvent.SetPosition(curPosition);
376 mDropTargets[i].callback(dragEvent);
383 bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
385 Ecore_Wl2_Event_Dnd_Drop* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Drop*>(event);
387 // Check the target object region
390 for(std::size_t i = 0; i < mDropTargets.size(); i++)
392 Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
393 Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
394 // If the drop position is in the target object region, request drop data to the source object
395 if(IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height))
398 mPosition = position;
399 Dali::Window window = Dali::DevelWindow::Get(mDropTargets[i].target);
401 char* mimetype = (char*)eina_array_data_get(ecore_wl2_offer_mimes_get(ev->offer), 0);
404 ecore_wl2_offer_receive(ev->offer, mimetype);
405 Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
406 Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
407 ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
416 } // namespace Adaptor
418 } // namespace Internal