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 ///////////////////////////////////////////////////////////////////////////////////////////////////
37 static bool IsIntersection(int px, int py, int tx, int ty, int tw, int th)
39 if(px > tx && py > ty && px < (tx + tw) && py < (ty + th))
46 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
48 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
49 dndImpl->SendData(event);
51 return ECORE_CALLBACK_PASS_ON;
54 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
56 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
57 dndImpl->ReceiveData(event);
59 return ECORE_CALLBACK_PASS_ON;
62 static Eina_Bool EcoreEventDataMotion(void* data, int type, void* event)
64 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
65 dndImpl->CalculateDragEvent(event);
67 return ECORE_CALLBACK_PASS_ON;
70 static Eina_Bool EcoreEventDataDrop(void* data, int type, void* event)
72 DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
73 dndImpl->CalculateViewRegion(event);
75 return ECORE_CALLBACK_PASS_ON;
78 Dali::DragAndDrop GetDragAndDrop()
80 Dali::DragAndDrop dnd;
82 Dali::SingletonService service(SingletonService::Get());
85 // Check whether the singleton is already created
86 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::DragAndDrop));
89 // If so, downcast the handle
90 dnd = Dali::DragAndDrop(dynamic_cast<DragAndDrop*>(handle.GetObjectPtr()));
94 // Create a singleon instance
95 DragAndDropEcoreWl* dndImpl = new DragAndDropEcoreWl();
97 dnd = Dali::DragAndDrop(dndImpl);
98 service.Register(typeid(Dali::DragAndDrop), dnd);
105 DragAndDropEcoreWl::DragAndDropEcoreWl()
107 mSendHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, this);
108 mReceiveHandler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, EcoreEventOfferDataReady, this);
109 mMotionHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, EcoreEventDataMotion, this);
110 mDropHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, EcoreEventDataDrop, this);
113 DragAndDropEcoreWl::~DragAndDropEcoreWl()
115 ecore_event_handler_del(mSendHandler);
116 ecore_event_handler_del(mReceiveHandler);
117 ecore_event_handler_del(mMotionHandler);
118 ecore_event_handler_del(mDropHandler);
121 bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const Dali::DragAndDrop::DragData& data)
124 auto parent = Dali::DevelWindow::Get(source);
126 // Set Drag Source Data
127 mMimeType = data.GetMimeType();
128 mData = data.GetData();
130 // Apply Shadow Property
131 shadow.SetProperty(Dali::Actor::Property::SIZE, Vector2(150, 150));
132 shadow.SetProperty(Dali::Actor::Property::OPACITY, 0.9f);
134 // Create Drag Window
135 mDragWindow = Dali::Window::New(Dali::PositionSize(0, 0, 150, 150), "DragWindow", "class", true);
136 mDragWindow.SetTransparency(true);
137 mDragWindow.SetSize(Dali::Window::WindowSize(150, 150));
138 mDragWindow.SetBackgroundColor(Color::TRANSPARENT);
139 mDragWindow.Add(shadow);
141 // Start Drag and Drop
142 Ecore_Wl2_Window* parentWindow = AnyCast<Ecore_Wl2_Window*>(parent.GetNativeHandle());
143 Ecore_Wl2_Window* dragWindow = AnyCast<Ecore_Wl2_Window*>(mDragWindow.GetNativeHandle());
144 Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
145 Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
147 // Disable Default Cursor
148 ecore_wl2_input_pointer_set(input, NULL, 0, 0);
150 // Set mime type for drag and drop
151 const char* mimeTypes[2];
152 mimeTypes[0] = mMimeType.c_str();
157 ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
159 // Start wayland drag and drop
160 mSerial = ecore_wl2_dnd_drag_start(input, parentWindow, dragWindow);
165 bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback)
167 std::vector<DropTarget>::iterator itr;
168 for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
170 if((*itr).target == target)
176 DropTarget targetData;
177 targetData.target = target;
178 targetData.callback = callback;
179 targetData.inside = false;
181 mDropTargets.push_back(targetData);
186 bool DragAndDropEcoreWl::RemoveListener(Dali::Actor target)
188 std::vector<DropTarget>::iterator itr;
189 for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
191 if((*itr).target == target)
193 mDropTargets.erase(itr);
201 void DragAndDropEcoreWl::SendData(void* event)
203 Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
204 if(ev->serial != mSerial)
209 int dataLength = strlen(mData.c_str());
210 int bufferSize = dataLength;
211 if((mMimeType.find("text") != std::string::npos) ||
212 (mMimeType.find("markup") != std::string::npos) ||
213 (mMimeType.find("image") != std::string::npos))
218 char* buffer = new char[bufferSize];
224 memcpy(buffer, mData.c_str(), dataLength);
225 buffer[dataLength] = '\0';
227 write(ev->fd, buffer, bufferSize);
238 void DragAndDropEcoreWl::ReceiveData(void* event)
240 Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
242 if(mTargetIndex != -1)
244 Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->mimetype, ev->data);
245 mDropTargets[mTargetIndex].callback(dragEvent);
246 mDropTargets[mTargetIndex].inside = false;
251 bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
253 Ecore_Wl2_Event_Dnd_Motion* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Motion*>(event);
255 Dali::DragAndDrop::DragEvent dragEvent;
256 Dali::Vector2 curPosition(ev->x, ev->y);
258 for(int i = 0; i < mDropTargets.size(); i++)
260 Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
261 Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
262 bool currentInside = IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height);
264 // Calculate Drag Enter, Leave, Move Event
265 if(currentInside && !mDropTargets[i].inside)
267 mDropTargets[i].inside = true;
269 dragEvent.SetAction(Dali::DragAndDrop::DragType::ENTER);
270 dragEvent.SetPosition(curPosition);
271 mDropTargets[i].callback(dragEvent);
273 else if(!currentInside && mDropTargets[i].inside)
275 mDropTargets[i].inside = false;
277 dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
278 dragEvent.SetPosition(curPosition);
279 mDropTargets[i].callback(dragEvent);
281 else if(currentInside && mDropTargets[i].inside)
284 dragEvent.SetAction(Dali::DragAndDrop::DragType::MOVE);
285 dragEvent.SetPosition(curPosition);
286 mDropTargets[i].callback(dragEvent);
293 bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
295 Ecore_Wl2_Event_Dnd_Drop* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Drop*>(event);
297 // Check the target object region
300 for(int i = 0; i < mDropTargets.size(); i++)
302 Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
303 Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
304 // If the drop position is in the target object region, request drop data to the source object
305 if(IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height))
308 mPosition = position;
309 Dali::Window window = Dali::DevelWindow::Get(mDropTargets[i].target);
311 char* mimetype = (char*)eina_array_data_get(ecore_wl2_offer_mimes_get(ev->offer), 0);
314 ecore_wl2_offer_accept(ev->offer, mimetype);
315 ecore_wl2_offer_receive(ev->offer, mimetype);
316 Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
317 Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
318 ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
327 } // namespace Adaptor
329 } // namespace Internal