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/internal/adaptor/tizen-wayland/dali-ecore-wl2.h>
23 #include <dali/devel-api/common/singleton-service.h>
24 #include <dali/integration-api/debug.h>
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////////////////////////////////////
38 static bool IsIntersection(int px, int py, int tx, int ty, int tw, int th)
40 if(px > tx && py > ty && px < (tx + tw) && py < (ty + th))
47 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
49 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
50 dndImpl->SendData(event);
52 return ECORE_CALLBACK_PASS_ON;
55 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
57 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
58 dndImpl->ReceiveData(event);
60 return ECORE_CALLBACK_PASS_ON;
63 static Eina_Bool EcoreEventDataMotion(void* data, int type, void* event)
65 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
66 dndImpl->CalculateDragEvent(event);
68 return ECORE_CALLBACK_PASS_ON;
71 static Eina_Bool EcoreEventDataDrop(void* data, int type, void* event)
73 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
74 dndImpl->CalculateViewRegion(event);
76 return ECORE_CALLBACK_PASS_ON;
80 Dali::DragAndDrop GetDragAndDrop()
82 Dali::DragAndDrop dnd;
84 Dali::SingletonService service(SingletonService::Get());
87 // Check whether the singleton is already created
88 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::DragAndDrop));
91 // If so, downcast the handle
92 dnd = Dali::DragAndDrop(dynamic_cast<DragAndDrop*>(handle.GetObjectPtr()));
96 // Create a singleon instance
97 DragAndDropEcoreWl *dndImpl = new DragAndDropEcoreWl();
99 dnd = Dali::DragAndDrop(dndImpl);
100 service.Register(typeid(Dali::DragAndDrop), dnd);
107 DragAndDropEcoreWl::DragAndDropEcoreWl()
109 mSendHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, this);
110 mReceiveHandler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, EcoreEventOfferDataReady, this);
111 mMotionHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, EcoreEventDataMotion, this);
112 mDropHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, EcoreEventDataDrop, this);
115 DragAndDropEcoreWl::~DragAndDropEcoreWl()
117 ecore_event_handler_del(mSendHandler);
118 ecore_event_handler_del(mReceiveHandler);
119 ecore_event_handler_del(mMotionHandler);
120 ecore_event_handler_del(mDropHandler);
123 void DragAndDropEcoreWl::SetData(std::string data)
129 bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData)
132 auto parent = Dali::DevelWindow::Get(source);
134 // Set Drag Source Data
137 // Apply Shadow Property
138 shadow.SetProperty(Dali::Actor::Property::SIZE, Vector2(150, 150));
139 shadow.SetProperty(Dali::Actor::Property::OPACITY, 0.9f);
141 // Create Drag Window
142 mDragWindow = Dali::Window::New(Dali::PositionSize(0, 0, 150, 150), "DragWindow", "class", true);
143 mDragWindow.SetTransparency(true);
144 mDragWindow.SetSize(Dali::Window::WindowSize(150, 150));
145 mDragWindow.SetBackgroundColor(Color::TRANSPARENT);
146 mDragWindow.Add(shadow);
148 // Start Drag and Drop
149 Ecore_Wl2_Window* parentWindow = AnyCast<Ecore_Wl2_Window*>(parent.GetNativeHandle());
150 Ecore_Wl2_Window* dragWindow = AnyCast<Ecore_Wl2_Window*>(mDragWindow.GetNativeHandle());
151 Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
152 Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
154 // TODO: Makes mime-type common
155 char *mimeTypes[2] = {"text/plain"};
159 ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
161 // Start wayland drag and drop
162 mSerial = ecore_wl2_dnd_drag_start(input, parentWindow, dragWindow);
167 bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback)
169 DropTarget targetData;
170 targetData.target = target;
171 targetData.callback = callback;
172 targetData.inside = false;
174 mDropTargets.push_back(targetData);
179 void DragAndDropEcoreWl::SendData(void* event)
181 Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
182 if(ev->serial != mSerial)
187 int len = strlen(mData.c_str());
188 char *buf = new char[len + 1];
189 strncpy(buf, mData.c_str(), len);
192 // Write source object data to target object
193 write(ev->fd, buf, len+1);
207 void DragAndDropEcoreWl::ReceiveData(void* event)
209 Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
211 if(mTargetIndex != -1)
213 Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->data);
214 mDropTargets[mTargetIndex].callback(dragEvent);
215 mDropTargets[mTargetIndex].inside = false;
220 bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
222 Ecore_Wl2_Event_Dnd_Motion *ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Motion*>(event);
224 Dali::DragAndDrop::DragEvent dragEvent;
225 Dali::Vector2 curPosition(ev->x, ev->y);
227 for(int i = 0; i < mDropTargets.size(); i++)
229 Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
230 Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
231 bool currentInside = IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height);
233 // Calculate Drag Enter, Leave, Move Event
234 if(currentInside && !mDropTargets[i].inside)
236 mDropTargets[i].inside = true;
238 dragEvent.SetAction(Dali::DragAndDrop::DragType::ENTER);
239 dragEvent.SetPosition(curPosition);
240 mDropTargets[i].callback(dragEvent);
242 else if(!currentInside && mDropTargets[i].inside)
244 mDropTargets[i].inside = false;
246 dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
247 dragEvent.SetPosition(curPosition);
248 mDropTargets[i].callback(dragEvent);
250 else if(currentInside && mDropTargets[i].inside)
253 dragEvent.SetAction(Dali::DragAndDrop::DragType::MOVE);
254 dragEvent.SetPosition(curPosition);
255 mDropTargets[i].callback(dragEvent);
262 bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
264 Ecore_Wl2_Event_Dnd_Drop *ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Drop*>(event);
266 // Check the target object region
269 for(int i = 0; i < mDropTargets.size(); i++)
271 Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
272 Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
273 // If the drop position is in the target object region, request drop data to the source object
274 if(IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height))
277 mPosition = position;
278 Dali::Window window = Dali::DevelWindow::Get(mDropTargets[i].target);
280 char *mimetype = (char*)eina_array_data_get(ecore_wl2_offer_mimes_get(ev->offer), 0);
283 ecore_wl2_offer_accept(ev->offer, mimetype);
284 ecore_wl2_offer_receive(ev->offer, mimetype);
285 Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
286 Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
287 ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
296 } // namespace Adaptor
298 } // namespace Internal