Merge "DALi Version 2.1.10" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / drag-and-drop / tizen-wayland / drag-and-drop-impl-ecore-wl2.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/drag-and-drop/tizen-wayland/drag-and-drop-impl-ecore-wl2.h>
20
21 // EXTERNAL INCLUDES
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>
25 #include <unistd.h>
26
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
28 // DragAndDrop
29 ///////////////////////////////////////////////////////////////////////////////////////////////////
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37
38 static bool IsIntersection(int px, int py, int tx, int ty, int tw, int th)
39 {
40   if(px > tx && py > ty && px < (tx + tw) && py < (ty + th))
41   {
42     return true;
43   }
44   return false;
45 }
46
47 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
48 {
49   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
50   dndImpl->SendData(event);
51
52   return ECORE_CALLBACK_PASS_ON;
53 }
54
55 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
56 {
57   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
58   dndImpl->ReceiveData(event);
59
60   return ECORE_CALLBACK_PASS_ON;
61 }
62
63 static Eina_Bool EcoreEventDataMotion(void* data, int type, void* event)
64 {
65   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
66   dndImpl->CalculateDragEvent(event);
67
68   return ECORE_CALLBACK_PASS_ON;
69 }
70
71 static Eina_Bool EcoreEventDataDrop(void* data, int type, void* event)
72 {
73   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
74   dndImpl->CalculateViewRegion(event);
75
76   return ECORE_CALLBACK_PASS_ON;
77 }
78
79
80 Dali::DragAndDrop GetDragAndDrop()
81 {
82   Dali::DragAndDrop dnd;
83
84   Dali::SingletonService service(SingletonService::Get());
85   if(service)
86   {
87     // Check whether the singleton is already created
88     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::DragAndDrop));
89     if(handle)
90     {
91       // If so, downcast the handle
92       dnd = Dali::DragAndDrop(dynamic_cast<DragAndDrop*>(handle.GetObjectPtr()));
93     }
94     else
95     {
96       // Create a singleon instance
97       DragAndDropEcoreWl *dndImpl = new DragAndDropEcoreWl();
98
99       dnd = Dali::DragAndDrop(dndImpl);
100       service.Register(typeid(Dali::DragAndDrop), dnd);
101     }
102   }
103
104   return dnd;
105 }
106
107 DragAndDropEcoreWl::DragAndDropEcoreWl()
108 {
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);
113 }
114
115 DragAndDropEcoreWl::~DragAndDropEcoreWl()
116 {
117   ecore_event_handler_del(mSendHandler);
118   ecore_event_handler_del(mReceiveHandler);
119   ecore_event_handler_del(mMotionHandler);
120   ecore_event_handler_del(mDropHandler);
121 }
122
123 void DragAndDropEcoreWl::SetData(std::string data)
124 {
125   // Save Data
126   mData = data;
127 }
128
129 bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData)
130 {
131   // Get Parent Window
132   auto parent = Dali::DevelWindow::Get(source);
133
134   // Set Drag Source Data
135   SetData(dragData);
136
137   // Apply Shadow Property
138   shadow.SetProperty(Dali::Actor::Property::SIZE, Vector2(150, 150));
139   shadow.SetProperty(Dali::Actor::Property::OPACITY, 0.9f);
140
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);
147
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);
153
154   // TODO: Makes mime-type common
155   char *mimeTypes[2] = {"text/plain"};
156   mimeTypes[1] = NULL;
157
158   // Set mimetype
159   ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
160
161   // Start wayland drag and drop
162   mSerial = ecore_wl2_dnd_drag_start(input, parentWindow, dragWindow);
163
164   return true;
165 }
166
167 bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback)
168 {
169   DropTarget targetData;
170   targetData.target = target;
171   targetData.callback = callback;
172   targetData.inside = false;
173
174   mDropTargets.push_back(targetData);
175
176   return true;
177 }
178
179 void DragAndDropEcoreWl::SendData(void* event)
180 {
181   Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
182   if(ev->serial != mSerial)
183   {
184     return;
185   }
186
187   int len = strlen(mData.c_str());
188   char *buf = new char[len + 1];
189   strncpy(buf, mData.c_str(), len);
190   buf[len] = '\0';
191
192   // Write source object data to target object
193   write(ev->fd, buf, len+1);
194   close(ev->fd);
195
196   if(mDragWindow)
197   {
198     mDragWindow.Hide();
199   }
200
201   if(buf)
202   {
203     free(buf);
204   }
205 }
206
207 void DragAndDropEcoreWl::ReceiveData(void* event)
208 {
209   Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
210
211   if(mTargetIndex != -1)
212   {
213     Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->data);
214     mDropTargets[mTargetIndex].callback(dragEvent);
215     mDropTargets[mTargetIndex].inside = false;
216   }
217   mTargetIndex = -1;
218 }
219
220 bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
221 {
222   Ecore_Wl2_Event_Dnd_Motion *ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Motion*>(event);
223
224   Dali::DragAndDrop::DragEvent dragEvent;
225   Dali::Vector2 curPosition(ev->x, ev->y);
226
227   for(int i = 0; i < mDropTargets.size(); i++)
228   {
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);
232
233     // Calculate Drag Enter, Leave, Move Event
234     if(currentInside && !mDropTargets[i].inside)
235     {
236       mDropTargets[i].inside = true;
237       // Call Enter Event
238       dragEvent.SetAction(Dali::DragAndDrop::DragType::ENTER);
239       dragEvent.SetPosition(curPosition);
240       mDropTargets[i].callback(dragEvent);
241     }
242     else if(!currentInside && mDropTargets[i].inside)
243     {
244       mDropTargets[i].inside = false;
245       // Call Leave Event
246       dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
247       dragEvent.SetPosition(curPosition);
248       mDropTargets[i].callback(dragEvent);
249     }
250     else if(currentInside && mDropTargets[i].inside)
251     {
252       // Call Move Event
253       dragEvent.SetAction(Dali::DragAndDrop::DragType::MOVE);
254       dragEvent.SetPosition(curPosition);
255       mDropTargets[i].callback(dragEvent);
256     }
257   }
258
259   return true;
260 }
261
262 bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
263 {
264   Ecore_Wl2_Event_Dnd_Drop *ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Drop*>(event);
265
266   // Check the target object region
267   mTargetIndex = -1;
268
269   for(int i = 0; i < mDropTargets.size(); i++)
270   {
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))
275     {
276       mTargetIndex = i;
277       mPosition = position;
278       Dali::Window window = Dali::DevelWindow::Get(mDropTargets[i].target);
279
280       char *mimetype = (char*)eina_array_data_get(ecore_wl2_offer_mimes_get(ev->offer), 0);
281       if(mimetype)
282       {
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));
288       }
289       return true;
290     }
291   }
292
293   return false;
294 }
295
296 } // namespace Adaptor
297
298 } // namespace Internal
299
300 } // namespace Dali