Calculate EncodedImageBuffer's hash in generate time
[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 static bool IsIntersection(int px, int py, int tx, int ty, int tw, int th)
38 {
39   if(px > tx && py > ty && px < (tx + tw) && py < (ty + th))
40   {
41     return true;
42   }
43   return false;
44 }
45
46 static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
47 {
48   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
49   dndImpl->SendData(event);
50
51   return ECORE_CALLBACK_PASS_ON;
52 }
53
54 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
55 {
56   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
57   dndImpl->ReceiveData(event);
58
59   return ECORE_CALLBACK_PASS_ON;
60 }
61
62 static Eina_Bool EcoreEventDataMotion(void* data, int type, void* event)
63 {
64   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
65   dndImpl->CalculateDragEvent(event);
66
67   return ECORE_CALLBACK_PASS_ON;
68 }
69
70 static Eina_Bool EcoreEventDataDrop(void* data, int type, void* event)
71 {
72   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
73   dndImpl->CalculateViewRegion(event);
74
75   return ECORE_CALLBACK_PASS_ON;
76 }
77
78 Dali::DragAndDrop GetDragAndDrop()
79 {
80   Dali::DragAndDrop dnd;
81
82   Dali::SingletonService service(SingletonService::Get());
83   if(service)
84   {
85     // Check whether the singleton is already created
86     Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::DragAndDrop));
87     if(handle)
88     {
89       // If so, downcast the handle
90       dnd = Dali::DragAndDrop(dynamic_cast<DragAndDrop*>(handle.GetObjectPtr()));
91     }
92     else
93     {
94       // Create a singleon instance
95       DragAndDropEcoreWl* dndImpl = new DragAndDropEcoreWl();
96
97       dnd = Dali::DragAndDrop(dndImpl);
98       service.Register(typeid(Dali::DragAndDrop), dnd);
99     }
100   }
101
102   return dnd;
103 }
104
105 DragAndDropEcoreWl::DragAndDropEcoreWl()
106 {
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);
111 }
112
113 DragAndDropEcoreWl::~DragAndDropEcoreWl()
114 {
115   ecore_event_handler_del(mSendHandler);
116   ecore_event_handler_del(mReceiveHandler);
117   ecore_event_handler_del(mMotionHandler);
118   ecore_event_handler_del(mDropHandler);
119 }
120
121 bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const Dali::DragAndDrop::DragData& data)
122 {
123   // Get Parent Window
124   auto parent = Dali::DevelWindow::Get(source);
125
126   // Set Drag Source Data
127   mMimeType = data.GetMimeType();
128   mData     = data.GetData();
129
130   // Apply Shadow Property
131   shadow.SetProperty(Dali::Actor::Property::SIZE, Vector2(150, 150));
132   shadow.SetProperty(Dali::Actor::Property::OPACITY, 0.9f);
133
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);
140
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);
146
147   // Disable Default Cursor
148   ecore_wl2_input_pointer_set(input, NULL, 0, 0);
149
150   // Set mime type for drag and drop
151   const char* mimeTypes[2];
152   mimeTypes[0] = mMimeType.c_str();
153   mimeTypes[1] = NULL;
154
155   // Set mime type
156   ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
157
158   // Start wayland drag and drop
159   mSerial = ecore_wl2_dnd_drag_start(input, parentWindow, dragWindow);
160
161   return true;
162 }
163
164 bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback)
165 {
166   std::vector<DropTarget>::iterator itr;
167   for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
168   {
169     if((*itr).target == target)
170     {
171       return false;
172     }
173   }
174
175   DropTarget targetData;
176   targetData.target   = target;
177   targetData.callback = callback;
178   targetData.inside   = false;
179
180   mDropTargets.push_back(targetData);
181
182   return true;
183 }
184
185 bool DragAndDropEcoreWl::RemoveListener(Dali::Actor target)
186 {
187   std::vector<DropTarget>::iterator itr;
188   for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
189   {
190     if((*itr).target == target)
191     {
192       mDropTargets.erase(itr);
193       break;
194     }
195   }
196
197   return true;
198 }
199
200 void DragAndDropEcoreWl::SendData(void* event)
201 {
202   Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
203   if(ev->serial != mSerial)
204   {
205     return;
206   }
207
208   int dataLength = strlen(mData.c_str());
209   int bufferSize = dataLength;
210   if((mMimeType.find("text") != std::string::npos) ||
211      (mMimeType.find("markup") != std::string::npos) ||
212      (mMimeType.find("image") != std::string::npos))
213   {
214     bufferSize += 1;
215   }
216
217   char* buffer = new char[bufferSize];
218   if(!buffer)
219   {
220     return;
221   }
222
223   memcpy(buffer, mData.c_str(), dataLength);
224   buffer[dataLength] = '\0';
225
226   auto ret = write(ev->fd, buffer, bufferSize);
227   if(DALI_UNLIKELY(ret != bufferSize))
228   {
229     DALI_LOG_ERROR("write(ev->fd) return %d! Pleacse check it\n", static_cast<int>(ret));
230   }
231
232   close(ev->fd);
233
234   if(mDragWindow)
235   {
236     mDragWindow.Hide();
237   }
238
239   delete[] buffer;
240 }
241
242 void DragAndDropEcoreWl::ReceiveData(void* event)
243 {
244   Ecore_Wl2_Event_Offer_Data_Ready* ev = reinterpret_cast<Ecore_Wl2_Event_Offer_Data_Ready*>(event);
245
246   if(mTargetIndex != -1)
247   {
248     Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->mimetype, ev->data);
249     mDropTargets[mTargetIndex].callback(dragEvent);
250     mDropTargets[mTargetIndex].inside = false;
251   }
252   mTargetIndex = -1;
253 }
254
255 bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
256 {
257   Ecore_Wl2_Event_Dnd_Motion* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Motion*>(event);
258
259   Dali::DragAndDrop::DragEvent dragEvent;
260   Dali::Vector2                curPosition(ev->x, ev->y);
261
262   for(std::size_t i = 0; i < mDropTargets.size(); i++)
263   {
264     Vector2 position      = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
265     Vector2 size          = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
266     bool    currentInside = IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height);
267
268     // Calculate Drag Enter, Leave, Move Event
269     if(currentInside && !mDropTargets[i].inside)
270     {
271       mDropTargets[i].inside = true;
272       // Call Enter Event
273       dragEvent.SetAction(Dali::DragAndDrop::DragType::ENTER);
274       dragEvent.SetPosition(curPosition);
275       mDropTargets[i].callback(dragEvent);
276     }
277     else if(!currentInside && mDropTargets[i].inside)
278     {
279       mDropTargets[i].inside = false;
280       // Call Leave Event
281       dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
282       dragEvent.SetPosition(curPosition);
283       mDropTargets[i].callback(dragEvent);
284     }
285     else if(currentInside && mDropTargets[i].inside)
286     {
287       // Call Move Event
288       dragEvent.SetAction(Dali::DragAndDrop::DragType::MOVE);
289       dragEvent.SetPosition(curPosition);
290       mDropTargets[i].callback(dragEvent);
291     }
292   }
293
294   return true;
295 }
296
297 bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
298 {
299   Ecore_Wl2_Event_Dnd_Drop* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Drop*>(event);
300
301   // Check the target object region
302   mTargetIndex = -1;
303
304   for(std::size_t i = 0; i < mDropTargets.size(); i++)
305   {
306     Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
307     Vector2 size     = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
308     // If the drop position is in the target object region, request drop data to the source object
309     if(IsIntersection(ev->x, ev->y, position.x, position.y, size.width, size.height))
310     {
311       mTargetIndex        = i;
312       mPosition           = position;
313       Dali::Window window = Dali::DevelWindow::Get(mDropTargets[i].target);
314
315       char* mimetype = (char*)eina_array_data_get(ecore_wl2_offer_mimes_get(ev->offer), 0);
316       if(mimetype)
317       {
318         ecore_wl2_offer_accept(ev->offer, mimetype);
319         ecore_wl2_offer_receive(ev->offer, mimetype);
320         Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
321         Ecore_Wl2_Input*   input   = ecore_wl2_input_default_input_get(display);
322         ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
323       }
324       return true;
325     }
326   }
327
328   return false;
329 }
330
331 } // namespace Adaptor
332
333 } // namespace Internal
334
335 } // namespace Dali