0176df6a91bdee528b9066c5ee9714c9691f2794
[platform/core/uifw/dali-extension.git] / dali-extension / internal / evas-plugin / evas-plugin-impl.cpp
1 /*
2  * Copyright (c) 2019 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 "evas-plugin-impl.h"
20
21 namespace Dali
22 {
23
24 namespace Extension
25 {
26
27 namespace Internal
28 {
29
30 namespace
31 {
32 const char* IMAGE_EVAS_OBJECT_NAME = "dali-evas-plugin";
33 const char* ELM_OBJECT_STYLE = "transparent";
34 const char* ELM_OBJECT_CONTAINER_PART_NAME = "elm.swallow.content";
35 }
36
37 struct EvasPlugin::Impl
38 {
39   Impl(EvasPlugin* evasPlugin, Evas_Object* parentEvasObject, int width, int height, bool transparent)
40   : mEvasPlugin(evasPlugin)
41   , mEcoreEvas(NULL)
42   , mImageEvasObject(NULL)
43   , mDaliAccessEvasObject(NULL)
44   , mDaliEvasObject(NULL)
45   {
46     Evas* evas = evas_object_evas_get(parentEvasObject);
47     mEcoreEvas = ecore_evas_ecore_evas_get(evas);
48
49     // Create the image evas object
50     mImageEvasObject = evas_object_image_filled_add(evas);
51     evas_object_name_set(mImageEvasObject, IMAGE_EVAS_OBJECT_NAME);
52     evas_object_image_content_hint_set(mImageEvasObject, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
53     evas_object_image_alpha_set(mImageEvasObject, transparent ? EINA_TRUE : EINA_FALSE);
54     evas_object_image_size_set(mImageEvasObject, width, height);
55     evas_object_size_hint_weight_set(mImageEvasObject, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
56     evas_object_size_hint_align_set(mImageEvasObject, EVAS_HINT_FILL, EVAS_HINT_FILL);
57
58     // Register the elm access to image evas object
59     mDaliAccessEvasObject = elm_access_object_register(mImageEvasObject, parentEvasObject);
60
61     // Create a button and set style as "focus", if does not want to show the focus, then "transparent"
62     mDaliEvasObject = elm_button_add(parentEvasObject);
63
64     // Don't need to show the focus boundary here
65     elm_object_style_set(mDaliEvasObject, ELM_OBJECT_STYLE);
66
67     // Set the image evas object to focus object, but event should not be propagated
68     elm_object_part_content_set(mDaliEvasObject, ELM_OBJECT_CONTAINER_PART_NAME, mImageEvasObject);
69     evas_object_propagate_events_set(mImageEvasObject, EINA_FALSE);
70
71     // Set the evas object you want to make focusable as the content of the swallow part
72     evas_object_size_hint_weight_set(mDaliEvasObject, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
73     evas_object_size_hint_align_set(mDaliEvasObject, EVAS_HINT_FILL, EVAS_HINT_FILL);
74
75     evas_object_move(mDaliEvasObject, 0, 0);
76     evas_object_resize(mDaliEvasObject, width, height);
77     evas_object_show(mDaliEvasObject);
78   }
79
80   ~Impl()
81   {
82     // Delete the elm focus evas object
83     evas_object_del(mDaliEvasObject);
84     mDaliEvasObject = NULL;
85
86     // Unregister elm_access_object
87     elm_access_object_unregister(mImageEvasObject);
88     mDaliAccessEvasObject = NULL;
89
90     // Delete the image evas object
91     evas_object_del(mImageEvasObject);
92     mImageEvasObject = NULL;
93   }
94
95   Ecore_Wl2_Window* GetNativeWindow()
96   {
97     return ecore_evas_wayland2_window_get( mEcoreEvas );
98   }
99
100   PositionSize GetGeometry()
101   {
102     PositionSize geometry;
103     evas_object_geometry_get(mImageEvasObject, &geometry.x, &geometry.y, &geometry.width, &geometry.height);
104     return geometry;
105   }
106
107   void SetFocus()
108   {
109     evas_object_focus_set(mImageEvasObject, EINA_TRUE);
110   }
111
112   void BindTBMSurface( tbm_surface_h surface )
113   {
114 #ifdef ENABLE_TTRACE
115     traceBegin( TTRACE_TAG_GRAPHICS, "EvasNativeSurfaceSet[%d]", pixmap );
116 #endif
117
118     Evas_Native_Surface nativeSurface;
119     nativeSurface.type = EVAS_NATIVE_SURFACE_TBM;
120     nativeSurface.version = EVAS_NATIVE_SURFACE_VERSION;
121     nativeSurface.data.tbm.buffer = surface;
122     nativeSurface.data.tbm.rot = 0;
123     nativeSurface.data.tbm.ratio = 0;
124     nativeSurface.data.tbm.flip = 0;
125
126     evas_object_image_native_surface_set( mImageEvasObject, &nativeSurface );
127
128 #ifdef ENABLE_TTRACE
129     traceEnd( TTRACE_TAG_GRAPHICS );
130 #endif
131   }
132
133   void RequestRender()
134   {
135     evas_object_image_pixels_dirty_set( mImageEvasObject, EINA_TRUE );
136     ecore_evas_manual_render( mEcoreEvas );
137   }
138
139   EvasPlugin* mEvasPlugin;
140   Ecore_Evas* mEcoreEvas;
141   Evas_Object* mImageEvasObject;
142   Evas_Object* mDaliAccessEvasObject;
143   Evas_Object* mDaliEvasObject;
144 };
145
146 EvasPluginPtr EvasPlugin::New(Evas_Object* parentEvasObject, int width, int height, bool transparent)
147 {
148   EvasPluginPtr evasPlugin = new EvasPlugin(parentEvasObject, width, height, transparent);
149   return evasPlugin;
150 }
151
152 EvasPlugin::EvasPlugin(Evas_Object* parentEvasObject, int width, int height, bool transparent)
153 : mState(READY)
154 , mTBMRenderSurface(NULL)
155 , mAdaptor(NULL)
156 , mRenderNotification(NULL)
157 , mEvasEventHandler(NULL)
158 , mEcoreWlEventHandler(NULL)
159 , mIsFocus(false)
160 , mTransparent(transparent)
161 , mImpl(NULL)
162 {
163   DALI_ASSERT_ALWAYS( parentEvasObject && "No parent object for the evas plugin." );
164
165   mImpl = new Impl(this, parentEvasObject, width, height, transparent);
166
167 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
168   // Create the singleton service
169   mSingletonService = SingletonService::New();
170
171   // Create the pixmap render surface
172   mTBMRenderSurface = CreateNativeSurface( PositionSize( 0, 0, width, height ), transparent );
173
174   // Initialize dali
175   Any nativeWindow = mImpl->GetNativeWindow();
176   mAdaptor = &Adaptor::New(nativeWindow, *mTBMRenderSurface, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS);
177 #endif
178
179 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
180   ImfManager imfManager = ImfManager::Get();
181   if(imfManager)
182   {
183     imfManager.ActivatedSignal().Connect(this, &EvasPlugin::OnImfActivated);
184   }
185 #endif
186
187 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
188   TriggerEventFactory triggerEventFactory;
189   mRenderNotification = triggerEventFactory.CreateTriggerEvent(MakeCallback(this, &EvasPlugin::OnPostRender),
190                                                                TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
191
192   mTBMRenderSurface->SetRenderNotification(mRenderNotification);
193 #endif
194 }
195
196 EvasPlugin::~EvasPlugin()
197 {
198 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
199   mAdaptor->Stop();
200
201   if (mEcoreWlEventHandler)
202   {
203     delete mEcoreWlEventHandler;
204     mEcoreWlEventHandler = NULL;
205   }
206
207   if (mEvasEventHandler)
208   {
209     delete mEvasEventHandler;
210     mEvasEventHandler = NULL;
211   }
212
213   delete mRenderNotification;
214   mRenderNotification = NULL;
215
216   // the singleton service should be unregistered before adaptor deletion
217   mSingletonService.UnregisterAll();
218
219   delete mAdaptor;
220   mAdaptor = NULL;
221
222   delete mTBMRenderSurface;
223   mTBMRenderSurface = NULL;
224 #endif
225
226   delete mImpl;
227   mImpl = NULL;
228 }
229
230 void EvasPlugin::Run()
231 {
232 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
233   if(READY == mState)
234   {
235     if (!mEvasEventHandler)
236     {
237       mEvasEventHandler = new Extension::Internal::EvasEventHandler(mImpl->mImageEvasObject, mImpl->mDaliAccessEvasObject, mImpl->mDaliEvasObject, *this);
238     }
239
240     // Start the adaptor
241     mAdaptor->Start();
242
243     mInitSignal.Emit();
244
245     mAdaptor->NotifySceneCreated();
246
247     mState = RUNNING;
248
249     DALI_LOG_RELEASE_INFO("EvasPlugin::Run");
250   }
251 #endif
252 }
253
254 void EvasPlugin::Pause()
255 {
256   if(mState == RUNNING)
257   {
258     mState = SUSPENDED;
259
260     mAdaptor->Pause();
261
262     mPauseSignal.Emit();
263
264     DALI_LOG_RELEASE_INFO("EvasPlugin::Pause");
265   }
266 }
267
268 void EvasPlugin::Resume()
269 {
270   if(mState == SUSPENDED)
271   {
272     mAdaptor->Resume();
273
274     mResumeSignal.Emit();
275
276     mState = RUNNING;
277
278     DALI_LOG_RELEASE_INFO("EvasPlugin::Resume");
279   }
280 }
281
282 void EvasPlugin::Stop()
283 {
284 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
285   if(mState != STOPPED)
286   {
287     // Stop the adaptor
288     mAdaptor->Stop();
289     mState = STOPPED;
290
291     mTerminateSignal.Emit();
292
293     DALI_LOG_RELEASE_INFO("EvasPlugin::Stop");
294   }
295 #endif
296 }
297
298 Evas_Object* EvasPlugin::GetDaliAccessEvasObject()
299 {
300   return mImpl->mDaliAccessEvasObject;
301 }
302
303 Evas_Object* EvasPlugin::GetDaliEvasObject()
304 {
305   return mImpl->mDaliEvasObject;
306 }
307
308 void EvasPlugin::ResizeSurface()
309 {
310 #if 0
311   // Remember old surface
312   NativeRenderSurface* oldSurface = mTBMRenderSurface;
313   TriggerEventInterface* oldTriggerEvent = mRenderNotification;
314
315   PositionSize geometry = mImpl->GetGeometry();
316
317   mAdaptor->SurfaceSizeChanged( geometry );
318
319   // emit resized signal to application
320   mResizeSignal.Emit();
321
322   mTBMRenderSurface = CreateNativeSurface( PositionSize( 0, 0, geometry.width, geometry.height ), NATIVE_SURFACE_NAME, mTransparent );
323   mTBMRenderSurface->SetRenderNotification( mRenderNotification );
324
325   // Ask the replace the surface inside dali
326   Any nativeWindow = mImpl->GetNativeWindow();
327
328   mAdaptor->ReplaceSurface( nativeWindow, *mTBMRenderSurface ); // this method is synchronous => guarantee until rendering next frame
329
330   TriggerEventFactory triggerEventFactory;
331   mRenderNotification = triggerEventFactory.CreateTriggerEvent( MakeCallback( this, &EvasPlugin::OnPostRender ),
332                                                                 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
333
334   mTBMRenderSurface->SetRenderNotification( mRenderNotification );
335   delete oldTriggerEvent;
336
337   // Bind offscreen surface to the evas object
338   mTBMRenderSurface->WaitUntilSurfaceReplaced();
339   mImpl->BindTBMSurface( AnyCast<tbm_surface_h>( mTBMRenderSurface->GetDrawable() ) );
340   mAdaptor->ReleaseSurfaceLock();
341
342   // It's now safe to delete the old surface
343   delete oldSurface;
344 #endif
345 }
346
347 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
348 void EvasPlugin::OnImfActivated(ImfManager& imfManager)
349 {
350   mImpl->SetFocus();
351 }
352 #endif
353
354 void EvasPlugin::OnPostRender()
355 {
356   // Bind offscreen surface to the evas object
357   mImpl->BindTBMSurface(AnyCast<tbm_surface_h>(mTBMRenderSurface->GetDrawable()));
358   mAdaptor->ReleaseSurfaceLock();
359
360   mImpl->RequestRender();
361 }
362
363 void EvasPlugin::OnEvasObjectTouchEvent(TouchPoint& touchPoint, unsigned long timeStamp)
364 {
365   mAdaptor->FeedTouchPoint(touchPoint, timeStamp);
366 }
367
368 void EvasPlugin::OnEvasObjectWheelEvent(WheelEvent& wheelEvent)
369 {
370   mAdaptor->FeedWheelEvent( wheelEvent );
371 }
372
373 void EvasPlugin::OnEvasObjectKeyEvent(KeyEvent& keyEvent)
374 {
375   mAdaptor->FeedKeyEvent( keyEvent );
376 }
377
378 void EvasPlugin::OnEvasObjectMove(const Rect<int>& geometry)
379 {
380 }
381
382 void EvasPlugin::OnEvasObjectResize(const Rect<int>& geometry)
383 {
384   DALI_LOG_RELEASE_INFO("EvasPlugin::OnEvasObjectResize (%d x %d)", geometry.width, geometry.height);
385
386   if (geometry.width <= 1 || geometry.height <= 1)
387   {
388     // skip meaningless resize signal
389     return;
390   }
391
392   Vector2 size = Stage::GetCurrent().GetSize();
393   if(size.width == geometry.width && size.height == geometry.height)
394   {
395     // skip meaningless resize signal
396     return;
397   }
398
399   ResizeSurface();
400 }
401
402 void EvasPlugin::OnEvasObjectFocusIn()
403 {
404   if(!mIsFocus)
405   {
406     if (!mEcoreWlEventHandler)
407     {
408       mEcoreWlEventHandler = new Extension::Internal::EcoreWlEventHandler(mImpl->GetNativeWindow(), *this);
409     }
410
411 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
412     ImfManager imfManager = ImfManager::Get();
413     if(imfManager)
414     {
415       // TODO : Move to Impl
416       Ecore_Wl_Window* window = mImpl->GetNativeWindow();
417       Ecore_IMF_Context* imfContext = Dali::Internal::Adaptor::ImfManager::GetImplementation(imfManager).GetContext();
418       ecore_imf_context_client_window_set( imfContext, reinterpret_cast<void*>( window ) );
419
420       if(imfManager.RestoreAfterFocusLost())
421       {
422         imfManager.Activate();
423       }
424     }
425 #endif
426
427     mFocusedSignal.Emit();
428
429     mIsFocus = true;
430
431     DALI_LOG_RELEASE_INFO("EvasPlugin::OnEvasObjectFocusIn");
432   }
433 }
434
435 void EvasPlugin::OnEvasObjectFocusOut()
436 {
437   if(mIsFocus)
438   {
439     mIsFocus = false;
440
441     if (mEcoreWlEventHandler)
442     {
443       delete mEcoreWlEventHandler;
444       mEcoreWlEventHandler = NULL;
445     }
446
447 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
448     ImfManager imfManager = ImfManager::Get();
449     if(imfManager && imfManager.RestoreAfterFocusLost())
450     {
451       imfManager.Deactivate();
452     }
453 #endif
454
455     Clipboard::Get().HideClipboard();
456
457     mUnFocusedSignal.Emit();
458
459     DALI_LOG_RELEASE_INFO("EvasPlugin::OnEvasObjectFocusOut");
460   }
461 }
462
463 void EvasPlugin::OnEvasPostRender()
464 {
465 }
466
467 bool EvasPlugin::OnElmAccessActionHighlight(AccessActionInfo& accessActionInfo)
468 {
469   return this->OnElmAccessibilityActionEvent(accessActionInfo);
470 }
471
472 bool EvasPlugin::OnElmAccessActionUnhighlight(AccessActionInfo& accessActionInfo)
473 {
474   return this->OnElmAccessibilityActionEvent(accessActionInfo);
475 }
476
477 bool EvasPlugin::OnElmAccessActionHighlightNext(AccessActionInfo& accessActionInfo)
478 {
479   return this->OnElmAccessibilityActionEvent(accessActionInfo);
480 }
481
482 bool EvasPlugin::OnElmAccessActionHighlightPrev(AccessActionInfo& accessActionInfo)
483 {
484   return this->OnElmAccessibilityActionEvent(accessActionInfo);
485 }
486
487 bool EvasPlugin::OnElmAccessActionActivate(AccessActionInfo& accessActionInfo)
488 {
489   return this->OnElmAccessibilityActionEvent(accessActionInfo);
490 }
491
492 bool EvasPlugin::OnElmAccessActionUp(AccessActionInfo& accessActionInfo)
493 {
494   return this->OnElmAccessibilityActionEvent(accessActionInfo);
495 }
496
497 bool EvasPlugin::OnElmAccessActionDown(AccessActionInfo& accessActionInfo)
498 {
499   return this->OnElmAccessibilityActionEvent(accessActionInfo);
500 }
501
502 bool EvasPlugin::OnElmAccessActionScroll(AccessActionInfo& accessActionInfo)
503 {
504   bool ret = false;
505
506   Evas_Coord rel_x, rel_y;
507   Evas_Coord obj_x,  obj_y, obj_w, obj_h;
508   Evas_Object* eo = this->GetDaliAccessEvasObject();
509
510   if(eo)
511   {
512     evas_object_geometry_get(eo, &obj_x,  &obj_y, &obj_w, &obj_h);
513
514     rel_x = accessActionInfo.x - obj_x;
515     rel_y = accessActionInfo.y - obj_y;
516
517     ret = this->OnElmAccessibilityActionEvent(accessActionInfo, rel_x, rel_y);
518   }
519
520   return ret;
521 }
522
523 bool EvasPlugin::OnElmAccessActionBack(AccessActionInfo& accessActionInfo)
524 {
525   return this->OnElmAccessibilityActionEvent(accessActionInfo);
526 }
527
528 bool EvasPlugin::OnElmAccessActionRead(AccessActionInfo& accessActionInfo)
529 {
530   return this->OnElmAccessibilityActionEvent(accessActionInfo);
531 }
532
533 void EvasPlugin::OnEcoreWlVisibility(bool visibility)
534 {
535   if (!visibility)
536   {
537     mAdaptor->ReleaseSurfaceLock();
538   }
539 }
540
541 bool EvasPlugin::OnElmAccessibilityActionEvent(AccessActionInfo& accessActionInfo, int x, int y)
542 {
543   bool ret = false;
544
545   if( NULL == mAdaptor)
546   {
547     return ret;
548   }
549
550   Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
551   if( accessibilityAdaptor )
552   {
553     int touchType = accessActionInfo.mouseType;
554     int touchX = x >= 0 ? x : accessActionInfo.x;
555     int touchY = y >= 0 ? y : accessActionInfo.y;
556
557     switch(accessActionInfo.actionBy)
558     {
559       case Dali::Extension::Internal::ACCESS_ACTION_HIGHLIGHT:
560       case Dali::Extension::Internal::ACCESS_ACTION_READ:
561       {
562         ret = accessibilityAdaptor.HandleActionReadEvent((unsigned int)x, (unsigned int)y, true);
563       }
564       break;
565
566       case Dali::Extension::Internal::ACCESS_ACTION_HIGHLIGHT_PREV:
567       {
568         // if accessActionInfo.highlight_end is true, need to handle end_of_list sound feedback
569         ret = accessibilityAdaptor.HandleActionPreviousEvent(accessActionInfo.highlightCycle);
570         if(!ret)
571         {
572           // when focus moving was failed, clear the focus
573           accessibilityAdaptor.HandleActionClearFocusEvent();
574         }
575       }
576       break;
577
578       case Dali::Extension::Internal::ACCESS_ACTION_HIGHLIGHT_NEXT:
579       {
580         // if accessActionInfo.highlight_cycle is true, need to handle end_of_list sound feedback
581         ret = accessibilityAdaptor.HandleActionNextEvent(accessActionInfo.highlightCycle);
582         if(!ret)
583         {
584           // when focus moving was failed, clear the focus
585           accessibilityAdaptor.HandleActionClearFocusEvent();
586         }
587       }
588       break;
589
590       case Dali::Extension::Internal::ACCESS_ACTION_ACTIVATE:
591       {
592         ret = accessibilityAdaptor.HandleActionActivateEvent();
593       }
594       break;
595
596       case Dali::Extension::Internal::ACCESS_ACTION_UNHIGHLIGHT:
597       {
598         ret = accessibilityAdaptor.HandleActionClearFocusEvent();
599       }
600       break;
601
602       case Dali::Extension::Internal::ACCESS_ACTION_SCROLL:
603       {
604         TouchPoint::State state(TouchPoint::Down);
605
606         if (touchType == 0)
607         {
608           state = TouchPoint::Down; // mouse down
609         }
610         else if (touchType == 1)
611         {
612           state = TouchPoint::Motion; // mouse move
613         }
614         else if (touchType == 2)
615         {
616           state = TouchPoint::Up; // mouse up
617         }
618         else
619         {
620           state = TouchPoint::Interrupted; // error
621         }
622
623         // Send touch event to accessibility manager.
624         TouchPoint point( 0, state, (float)touchX, (float)touchY );
625         ret = accessibilityAdaptor.HandleActionScrollEvent(point, accessActionInfo.timeStamp);
626       }
627       break;
628
629       case Dali::Extension::Internal::ACCESS_ACTION_UP:
630       {
631         ret = accessibilityAdaptor.HandleActionUpEvent();
632       }
633       break;
634
635       case Dali::Extension::Internal::ACCESS_ACTION_DOWN:
636       {
637         ret = accessibilityAdaptor.HandleActionDownEvent();
638       }
639       break;
640
641         case Dali::Extension::Internal::ACCESS_ACTION_BACK:
642       default:
643       {
644         DALI_LOG_WARNING("[%s:%d]\n", __FUNCTION__, __LINE__);
645       }
646
647       break;
648     }
649   }
650   else
651   {
652     DALI_LOG_WARNING("[%s:%d]\n", __FUNCTION__, __LINE__);
653   }
654
655   DALI_LOG_INFO(gEvasPluginLogFilter, Debug::General, "[%s:%d] [action : %d] focus manager returns %s\n", __FUNCTION__, __LINE__, (int)(actionType), ret?"TRUE":"FALSE");
656
657   return ret;
658 }
659
660 } // namespace Internal
661
662 } // namespace Extension
663
664 } // namespace Dali