Merge "Fix svace issue for image-operator" 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/devel-api/common/singleton-service.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h>
25 #include <unistd.h>
26
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
28 // DragAndDrop
29 ///////////////////////////////////////////////////////////////////////////////////////////////////
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 namespace
38 {
39 static constexpr int32_t DEFAULT_POSITION = -1;
40 }
41
42 static bool IsIntersection(int px, int py, int tx, int ty, int tw, int th)
43 {
44   if(px > tx && py > ty && px < (tx + tw) && py < (ty + th))
45   {
46     return true;
47   }
48   return false;
49 }
50
51 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
52 {
53   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
54   dndImpl->SendData(event);
55
56   return ECORE_CALLBACK_PASS_ON;
57 }
58
59 static Eina_Bool EcoreEventDataSourceEnd(void* data, int type, void* event)
60 {
61   Ecore_Wl2_Event_Data_Source_End *ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_End*>(event);
62   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
63   if(ev->cancelled)
64   {
65     dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::CANCEL);
66   }
67   else
68   {
69     dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::ACCEPT);
70   }
71
72   return ECORE_CALLBACK_PASS_ON;
73 }
74
75 static Eina_Bool EcoreEventDataSourceDrop(void* data, int type, void* event)
76 {
77   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
78   dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::FINISH);
79   return ECORE_CALLBACK_PASS_ON;
80 }
81
82 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
83 {
84   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
85   dndImpl->ReceiveData(event);
86
87   return ECORE_CALLBACK_PASS_ON;
88 }
89
90 static Eina_Bool EcoreEventDataMotion(void* data, int type, void* event)
91 {
92   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
93   dndImpl->CalculateDragEvent(event);
94
95   return ECORE_CALLBACK_PASS_ON;
96 }
97
98 static Eina_Bool EcoreEventDataDrop(void* data, int type, void* event)
99 {
100   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
101   dndImpl->CalculateViewRegion(event);
102
103   return ECORE_CALLBACK_PASS_ON;
104 }
105
106 static Eina_Bool EcoreEventDataEnter(void* data, int type, void* event)
107 {
108   Ecore_Wl2_Event_Dnd_Enter* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Enter*>(event);
109
110   // Set default offer is reject
111   ecore_wl2_offer_accept(ev->offer, NULL);
112   return ECORE_CALLBACK_PASS_ON;
113 }
114
115 static Eina_Bool EcoreEventDataLeave(void* data, int type, void* event)
116 {
117   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
118   dndImpl->ResetDropTargets();
119
120   return ECORE_CALLBACK_PASS_ON;
121 }
122
123 Dali::DragAndDrop GetDragAndDrop()
124 {
125   Dali::DragAndDrop dnd;
126
127   Dali::SingletonService service(SingletonService::Get());
128   if(service)
129   {
130     // Check whether the singleton is already created
131     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::DragAndDrop));
132     if(handle)
133     {
134       // If so, downcast the handle
135       dnd = Dali::DragAndDrop(dynamic_cast<DragAndDrop*>(handle.GetObjectPtr()));
136     }
137     else
138     {
139       // Create a singleon instance
140       DragAndDropEcoreWl* dndImpl = new DragAndDropEcoreWl();
141
142       dnd = Dali::DragAndDrop(dndImpl);
143       service.Register(typeid(Dali::DragAndDrop), dnd);
144     }
145   }
146
147   return dnd;
148 }
149
150 DragAndDropEcoreWl::DragAndDropEcoreWl()
151 {
152   // Source Events
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);
156
157   // Target Events
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);
163 }
164
165 DragAndDropEcoreWl::~DragAndDropEcoreWl()
166 {
167   // Source Events
168   ecore_event_handler_del(mSendHandler);
169   ecore_event_handler_del(mSourceEndHandler);
170   ecore_event_handler_del(mSourceDropHandler);
171
172   // Target Events
173   ecore_event_handler_del(mReceiveHandler);
174   ecore_event_handler_del(mMotionHandler);
175   ecore_event_handler_del(mDropHandler);
176   ecore_event_handler_del(mEnterHandler);
177 }
178
179 bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const Dali::DragAndDrop::DragData& data, Dali::DragAndDrop::SourceFunction callback)
180 {
181   // Get Parent Window
182   auto parent = Dali::DevelWindow::Get(source);
183
184   // Set Drag Source Data
185   mMimeType = data.GetMimeType();
186   mData     = data.GetData();
187
188   // Set Source Event
189   mSourceCallback = callback;
190
191   // Set Drag Window
192   mDragWindow = shadowWindow;
193
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);
199
200   // Disable Default Cursor
201   ecore_wl2_input_pointer_set(input, NULL, 0, 0);
202
203   // Set mime type for drag and drop
204   const char* mimeTypes[2];
205   mimeTypes[0] = mMimeType.c_str();
206   mimeTypes[1] = NULL;
207
208   // Set mime type
209   ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
210
211   // Start wayland drag and drop
212   mSerial = ecore_wl2_dnd_drag_start(input, parentWindow, dragWindow);
213
214   // Call Start Event
215   CallSourceEvent(Dali::DragAndDrop::SourceEventType::START);
216
217   return true;
218 }
219
220 bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback)
221 {
222   std::vector<DropTarget>::iterator itr;
223   for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
224   {
225     if((*itr).target == target)
226     {
227       return false;
228     }
229   }
230
231   auto parent = Dali::DevelWindow::Get(target);
232   Ecore_Wl2_Window*  parentWindow = AnyCast<Ecore_Wl2_Window*>(parent.GetNativeHandle());
233   if(parentWindow == nullptr)
234   {
235     return false;
236   }
237
238   DropTarget targetData;
239   targetData.target   = target;
240   targetData.callback = callback;
241   targetData.inside   = false;
242   targetData.parentWindowId = ecore_wl2_window_id_get(parentWindow);
243
244   mDropTargets.push_back(targetData);
245
246   return true;
247 }
248
249 bool DragAndDropEcoreWl::RemoveListener(Dali::Actor target)
250 {
251   std::vector<DropTarget>::iterator itr;
252   for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
253   {
254     if((*itr).target == target)
255     {
256       mDropTargets.erase(itr);
257       break;
258     }
259   }
260
261   return true;
262 }
263
264 void DragAndDropEcoreWl::CallSourceEvent(Dali::DragAndDrop::SourceEventType type)
265 {
266   if(mSourceCallback)
267   {
268     mSourceCallback(type);
269   }
270 }
271
272 void DragAndDropEcoreWl::ResetDropTargets()
273 {
274   for(std::size_t i = 0; i < mDropTargets.size(); i++)
275   {
276      if(mDropTargets[i].inside)
277      {
278        Dali::DragAndDrop::DragEvent dragEvent;
279        dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
280        Dali::Vector2 position(DEFAULT_POSITION, DEFAULT_POSITION);
281        dragEvent.SetPosition(position);
282        mDropTargets[i].callback(dragEvent);
283      }
284      mDropTargets[i].inside = false;
285   }
286 }
287
288
289 void DragAndDropEcoreWl::SendData(void* event)
290 {
291   Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
292   if(ev->serial != mSerial)
293   {
294     return;
295   }
296
297   int dataLength = strlen(mData.c_str());
298   int bufferSize = dataLength;
299   if((mMimeType.find("text") != std::string::npos) ||
300      (mMimeType.find("markup") != std::string::npos) ||
301      (mMimeType.find("image") != std::string::npos))
302   {
303     bufferSize += 1;
304   }
305
306   char* buffer = new char[bufferSize];
307   if(!buffer)
308   {
309     return;
310   }
311
312   memcpy(buffer, mData.c_str(), dataLength);
313   buffer[dataLength] = '\0';
314
315   auto ret = write(ev->fd, buffer, bufferSize);
316   if(DALI_UNLIKELY(ret != bufferSize))
317   {
318     DALI_LOG_ERROR("write(ev->fd) return %d! Pleacse check it\n", static_cast<int>(ret));
319   }
320
321   close(ev->fd);
322
323   if(mDragWindow)
324   {
325     mDragWindow.Hide();
326   }
327
328   delete[] buffer;
329 }
330
331 void DragAndDropEcoreWl::ReceiveData(void* event)
332 {
333   Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
334
335   if(mTargetIndex != -1)
336   {
337     Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->mimetype, ev->data);
338     mDropTargets[mTargetIndex].callback(dragEvent);
339     mDropTargets[mTargetIndex].inside = false;
340     ecore_wl2_offer_finish(ev->offer);
341   }
342   mTargetIndex = -1;
343 }
344
345 bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
346 {
347   Ecore_Wl2_Event_Dnd_Motion* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Motion*>(event);
348
349   Dali::DragAndDrop::DragEvent dragEvent;
350   Dali::Vector2                curPosition(ev->x, ev->y);
351
352   for(std::size_t i = 0; i < mDropTargets.size(); i++)
353   {
354     if(ev->win != mDropTargets[i].parentWindowId)
355     {
356       continue;
357     }
358
359     Vector2 position      = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
360     Vector2 size          = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
361     bool    currentInside = IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height);
362
363     // Calculate Drag Enter, Leave, Move Event
364     if(currentInside && !mDropTargets[i].inside)
365     {
366       mDropTargets[i].inside = true;
367       // Call Enter Event
368       dragEvent.SetAction(Dali::DragAndDrop::DragType::ENTER);
369       dragEvent.SetPosition(curPosition);
370       mDropTargets[i].callback(dragEvent);
371       // Accept Offer
372       ecore_wl2_offer_mimes_set(ev->offer, ecore_wl2_offer_mimes_get(ev->offer));
373     }
374     else if(!currentInside && mDropTargets[i].inside)
375     {
376       mDropTargets[i].inside = false;
377       // Call Leave Event
378       dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
379       dragEvent.SetPosition(curPosition);
380       mDropTargets[i].callback(dragEvent);
381       // Reject Offer
382       ecore_wl2_offer_accept(ev->offer, NULL);
383     }
384     else if(currentInside && mDropTargets[i].inside)
385     {
386       // Call Move Event
387       dragEvent.SetAction(Dali::DragAndDrop::DragType::MOVE);
388       dragEvent.SetPosition(curPosition);
389       mDropTargets[i].callback(dragEvent);
390     }
391   }
392
393   return true;
394 }
395
396 bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
397 {
398   Ecore_Wl2_Event_Dnd_Drop* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Drop*>(event);
399
400   // Check the target object region
401   mTargetIndex = -1;
402
403   for(std::size_t i = 0; i < mDropTargets.size(); i++)
404   {
405     if(ev->win != mDropTargets[i].parentWindowId)
406     {
407       continue;
408     }
409
410     Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
411     Vector2 size     = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
412     // If the drop position is in the target object region, request drop data to the source object
413     if(IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height))
414     {
415       mTargetIndex        = i;
416       mPosition           = position;
417       Dali::Window window = Dali::DevelWindow::Get(mDropTargets[i].target);
418
419       char* mimetype = (char*)eina_array_data_get(ecore_wl2_offer_mimes_get(ev->offer), 0);
420       if(mimetype)
421       {
422         ecore_wl2_offer_receive(ev->offer, mimetype);
423         Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
424         Ecore_Wl2_Input*   input   = ecore_wl2_input_default_input_get(display);
425         ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
426       }
427       return true;
428     }
429   }
430
431   return false;
432 }
433
434 } // namespace Adaptor
435
436 } // namespace Internal
437
438 } // namespace Dali