2 * Copyright (c) 2019 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 "evas-plugin-impl.h"
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";
37 struct EvasPlugin::Impl
39 Impl(EvasPlugin* evasPlugin, Evas_Object* parentEvasObject, int width, int height, bool transparent)
40 : mEvasPlugin(evasPlugin)
42 , mImageEvasObject(NULL)
43 , mDaliAccessEvasObject(NULL)
44 , mDaliEvasObject(NULL)
46 Evas* evas = evas_object_evas_get(parentEvasObject);
47 mEcoreEvas = ecore_evas_ecore_evas_get(evas);
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);
58 // Register the elm access to image evas object
59 mDaliAccessEvasObject = elm_access_object_register(mImageEvasObject, parentEvasObject);
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);
64 // Don't need to show the focus boundary here
65 elm_object_style_set(mDaliEvasObject, ELM_OBJECT_STYLE);
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);
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);
75 evas_object_move(mDaliEvasObject, 0, 0);
76 evas_object_resize(mDaliEvasObject, width, height);
77 evas_object_show(mDaliEvasObject);
82 // Delete the elm focus evas object
83 evas_object_del(mDaliEvasObject);
84 mDaliEvasObject = NULL;
86 // Unregister elm_access_object
87 elm_access_object_unregister(mImageEvasObject);
88 mDaliAccessEvasObject = NULL;
90 // Delete the image evas object
91 evas_object_del(mImageEvasObject);
92 mImageEvasObject = NULL;
95 Ecore_Wl2_Window* GetNativeWindow()
97 return ecore_evas_wayland2_window_get( mEcoreEvas );
100 PositionSize GetGeometry()
102 PositionSize geometry;
103 evas_object_geometry_get(mImageEvasObject, &geometry.x, &geometry.y, &geometry.width, &geometry.height);
109 evas_object_focus_set(mImageEvasObject, EINA_TRUE);
112 void BindTBMSurface( tbm_surface_h surface )
115 traceBegin( TTRACE_TAG_GRAPHICS, "EvasNativeSurfaceSet[%d]", pixmap );
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;
126 evas_object_image_native_surface_set( mImageEvasObject, &nativeSurface );
129 traceEnd( TTRACE_TAG_GRAPHICS );
135 evas_object_image_pixels_dirty_set( mImageEvasObject, EINA_TRUE );
136 ecore_evas_manual_render( mEcoreEvas );
139 EvasPlugin* mEvasPlugin;
140 Ecore_Evas* mEcoreEvas;
141 Evas_Object* mImageEvasObject;
142 Evas_Object* mDaliAccessEvasObject;
143 Evas_Object* mDaliEvasObject;
146 EvasPluginPtr EvasPlugin::New(Evas_Object* parentEvasObject, int width, int height, bool transparent)
148 EvasPluginPtr evasPlugin = new EvasPlugin(parentEvasObject, width, height, transparent);
152 EvasPlugin::EvasPlugin(Evas_Object* parentEvasObject, int width, int height, bool transparent)
154 , mTBMRenderSurface(NULL)
156 , mRenderNotification(NULL)
157 , mEvasEventHandler(NULL)
158 , mEcoreWlEventHandler(NULL)
160 , mTransparent(transparent)
163 DALI_ASSERT_ALWAYS( parentEvasObject && "No parent object for the evas plugin." );
165 mImpl = new Impl(this, parentEvasObject, width, height, transparent);
167 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
168 // Create the singleton service
169 mSingletonService = SingletonService::New();
171 // Create the pixmap render surface
172 mTBMRenderSurface = CreateNativeSurface( PositionSize( 0, 0, width, height ), transparent );
175 Any nativeWindow = mImpl->GetNativeWindow();
176 mAdaptor = &Adaptor::New(nativeWindow, *mTBMRenderSurface, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS);
179 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
180 ImfManager imfManager = ImfManager::Get();
183 imfManager.ActivatedSignal().Connect(this, &EvasPlugin::OnImfActivated);
187 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
188 TriggerEventFactory triggerEventFactory;
189 mRenderNotification = triggerEventFactory.CreateTriggerEvent(MakeCallback(this, &EvasPlugin::OnPostRender),
190 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
192 mTBMRenderSurface->SetRenderNotification(mRenderNotification);
196 EvasPlugin::~EvasPlugin()
198 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
201 if (mEcoreWlEventHandler)
203 delete mEcoreWlEventHandler;
204 mEcoreWlEventHandler = NULL;
207 if (mEvasEventHandler)
209 delete mEvasEventHandler;
210 mEvasEventHandler = NULL;
213 delete mRenderNotification;
214 mRenderNotification = NULL;
216 // the singleton service should be unregistered before adaptor deletion
217 mSingletonService.UnregisterAll();
222 delete mTBMRenderSurface;
223 mTBMRenderSurface = NULL;
230 void EvasPlugin::Run()
232 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
235 if (!mEvasEventHandler)
237 mEvasEventHandler = new Extension::Internal::EvasEventHandler(mImpl->mImageEvasObject, mImpl->mDaliAccessEvasObject, mImpl->mDaliEvasObject, *this);
245 mAdaptor->NotifySceneCreated();
249 DALI_LOG_RELEASE_INFO("EvasPlugin::Run");
254 void EvasPlugin::Pause()
256 if(mState == RUNNING)
264 DALI_LOG_RELEASE_INFO("EvasPlugin::Pause");
268 void EvasPlugin::Resume()
270 if(mState == SUSPENDED)
274 mResumeSignal.Emit();
278 DALI_LOG_RELEASE_INFO("EvasPlugin::Resume");
282 void EvasPlugin::Stop()
284 #ifdef DALI_PREVENT_TIZEN_40_FEATURE
285 if(mState != STOPPED)
291 mTerminateSignal.Emit();
293 DALI_LOG_RELEASE_INFO("EvasPlugin::Stop");
298 Evas_Object* EvasPlugin::GetDaliAccessEvasObject()
300 return mImpl->mDaliAccessEvasObject;
303 Evas_Object* EvasPlugin::GetDaliEvasObject()
305 return mImpl->mDaliEvasObject;
308 void EvasPlugin::ResizeSurface()
311 // Remember old surface
312 NativeRenderSurface* oldSurface = mTBMRenderSurface;
313 TriggerEventInterface* oldTriggerEvent = mRenderNotification;
315 PositionSize geometry = mImpl->GetGeometry();
317 mAdaptor->SurfaceSizeChanged( geometry );
319 // emit resized signal to application
320 mResizeSignal.Emit();
322 mTBMRenderSurface = CreateNativeSurface( PositionSize( 0, 0, geometry.width, geometry.height ), NATIVE_SURFACE_NAME, mTransparent );
323 mTBMRenderSurface->SetRenderNotification( mRenderNotification );
325 // Ask the replace the surface inside dali
326 Any nativeWindow = mImpl->GetNativeWindow();
328 mAdaptor->ReplaceSurface( nativeWindow, *mTBMRenderSurface ); // this method is synchronous => guarantee until rendering next frame
330 TriggerEventFactory triggerEventFactory;
331 mRenderNotification = triggerEventFactory.CreateTriggerEvent( MakeCallback( this, &EvasPlugin::OnPostRender ),
332 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
334 mTBMRenderSurface->SetRenderNotification( mRenderNotification );
335 delete oldTriggerEvent;
337 // Bind offscreen surface to the evas object
338 mTBMRenderSurface->WaitUntilSurfaceReplaced();
339 mImpl->BindTBMSurface( AnyCast<tbm_surface_h>( mTBMRenderSurface->GetDrawable() ) );
340 mAdaptor->ReleaseSurfaceLock();
342 // It's now safe to delete the old surface
347 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
348 void EvasPlugin::OnImfActivated(ImfManager& imfManager)
354 void EvasPlugin::OnPostRender()
356 // Bind offscreen surface to the evas object
357 mImpl->BindTBMSurface(AnyCast<tbm_surface_h>(mTBMRenderSurface->GetDrawable()));
358 mAdaptor->ReleaseSurfaceLock();
360 mImpl->RequestRender();
363 void EvasPlugin::OnEvasObjectTouchEvent(TouchPoint& touchPoint, unsigned long timeStamp)
365 mAdaptor->FeedTouchPoint(touchPoint, timeStamp);
368 void EvasPlugin::OnEvasObjectWheelEvent(WheelEvent& wheelEvent)
370 mAdaptor->FeedWheelEvent( wheelEvent );
373 void EvasPlugin::OnEvasObjectKeyEvent(KeyEvent& keyEvent)
375 mAdaptor->FeedKeyEvent( keyEvent );
378 void EvasPlugin::OnEvasObjectMove(const Rect<int>& geometry)
382 void EvasPlugin::OnEvasObjectResize(const Rect<int>& geometry)
384 DALI_LOG_RELEASE_INFO("EvasPlugin::OnEvasObjectResize (%d x %d)", geometry.width, geometry.height);
386 if (geometry.width <= 1 || geometry.height <= 1)
388 // skip meaningless resize signal
392 Vector2 size = Stage::GetCurrent().GetSize();
393 if(size.width == geometry.width && size.height == geometry.height)
395 // skip meaningless resize signal
402 void EvasPlugin::OnEvasObjectFocusIn()
406 if (!mEcoreWlEventHandler)
408 mEcoreWlEventHandler = new Extension::Internal::EcoreWlEventHandler(mImpl->GetNativeWindow(), *this);
411 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
412 ImfManager imfManager = ImfManager::Get();
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 ) );
420 if(imfManager.RestoreAfterFocusLost())
422 imfManager.Activate();
427 mFocusedSignal.Emit();
431 DALI_LOG_RELEASE_INFO("EvasPlugin::OnEvasObjectFocusIn");
435 void EvasPlugin::OnEvasObjectFocusOut()
441 if (mEcoreWlEventHandler)
443 delete mEcoreWlEventHandler;
444 mEcoreWlEventHandler = NULL;
447 #ifdef DALI_EVASPLUGIN_USE_IMF_MANAGER
448 ImfManager imfManager = ImfManager::Get();
449 if(imfManager && imfManager.RestoreAfterFocusLost())
451 imfManager.Deactivate();
455 Clipboard::Get().HideClipboard();
457 mUnFocusedSignal.Emit();
459 DALI_LOG_RELEASE_INFO("EvasPlugin::OnEvasObjectFocusOut");
463 void EvasPlugin::OnEvasPostRender()
467 bool EvasPlugin::OnElmAccessActionHighlight(AccessActionInfo& accessActionInfo)
469 return this->OnElmAccessibilityActionEvent(accessActionInfo);
472 bool EvasPlugin::OnElmAccessActionUnhighlight(AccessActionInfo& accessActionInfo)
474 return this->OnElmAccessibilityActionEvent(accessActionInfo);
477 bool EvasPlugin::OnElmAccessActionHighlightNext(AccessActionInfo& accessActionInfo)
479 return this->OnElmAccessibilityActionEvent(accessActionInfo);
482 bool EvasPlugin::OnElmAccessActionHighlightPrev(AccessActionInfo& accessActionInfo)
484 return this->OnElmAccessibilityActionEvent(accessActionInfo);
487 bool EvasPlugin::OnElmAccessActionActivate(AccessActionInfo& accessActionInfo)
489 return this->OnElmAccessibilityActionEvent(accessActionInfo);
492 bool EvasPlugin::OnElmAccessActionUp(AccessActionInfo& accessActionInfo)
494 return this->OnElmAccessibilityActionEvent(accessActionInfo);
497 bool EvasPlugin::OnElmAccessActionDown(AccessActionInfo& accessActionInfo)
499 return this->OnElmAccessibilityActionEvent(accessActionInfo);
502 bool EvasPlugin::OnElmAccessActionScroll(AccessActionInfo& accessActionInfo)
506 Evas_Coord rel_x, rel_y;
507 Evas_Coord obj_x, obj_y, obj_w, obj_h;
508 Evas_Object* eo = this->GetDaliAccessEvasObject();
512 evas_object_geometry_get(eo, &obj_x, &obj_y, &obj_w, &obj_h);
514 rel_x = accessActionInfo.x - obj_x;
515 rel_y = accessActionInfo.y - obj_y;
517 ret = this->OnElmAccessibilityActionEvent(accessActionInfo, rel_x, rel_y);
523 bool EvasPlugin::OnElmAccessActionBack(AccessActionInfo& accessActionInfo)
525 return this->OnElmAccessibilityActionEvent(accessActionInfo);
528 bool EvasPlugin::OnElmAccessActionRead(AccessActionInfo& accessActionInfo)
530 return this->OnElmAccessibilityActionEvent(accessActionInfo);
533 void EvasPlugin::OnEcoreWlVisibility(bool visibility)
537 mAdaptor->ReleaseSurfaceLock();
541 bool EvasPlugin::OnElmAccessibilityActionEvent(AccessActionInfo& accessActionInfo, int x, int y)
545 if( NULL == mAdaptor)
550 Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
551 if( accessibilityAdaptor )
553 int touchType = accessActionInfo.mouseType;
554 int touchX = x >= 0 ? x : accessActionInfo.x;
555 int touchY = y >= 0 ? y : accessActionInfo.y;
557 switch(accessActionInfo.actionBy)
559 case Dali::Extension::Internal::ACCESS_ACTION_HIGHLIGHT:
560 case Dali::Extension::Internal::ACCESS_ACTION_READ:
562 ret = accessibilityAdaptor.HandleActionReadEvent((unsigned int)x, (unsigned int)y, true);
566 case Dali::Extension::Internal::ACCESS_ACTION_HIGHLIGHT_PREV:
568 // if accessActionInfo.highlight_end is true, need to handle end_of_list sound feedback
569 ret = accessibilityAdaptor.HandleActionPreviousEvent(accessActionInfo.highlightCycle);
572 // when focus moving was failed, clear the focus
573 accessibilityAdaptor.HandleActionClearFocusEvent();
578 case Dali::Extension::Internal::ACCESS_ACTION_HIGHLIGHT_NEXT:
580 // if accessActionInfo.highlight_cycle is true, need to handle end_of_list sound feedback
581 ret = accessibilityAdaptor.HandleActionNextEvent(accessActionInfo.highlightCycle);
584 // when focus moving was failed, clear the focus
585 accessibilityAdaptor.HandleActionClearFocusEvent();
590 case Dali::Extension::Internal::ACCESS_ACTION_ACTIVATE:
592 ret = accessibilityAdaptor.HandleActionActivateEvent();
596 case Dali::Extension::Internal::ACCESS_ACTION_UNHIGHLIGHT:
598 ret = accessibilityAdaptor.HandleActionClearFocusEvent();
602 case Dali::Extension::Internal::ACCESS_ACTION_SCROLL:
604 TouchPoint::State state(TouchPoint::Down);
608 state = TouchPoint::Down; // mouse down
610 else if (touchType == 1)
612 state = TouchPoint::Motion; // mouse move
614 else if (touchType == 2)
616 state = TouchPoint::Up; // mouse up
620 state = TouchPoint::Interrupted; // error
623 // Send touch event to accessibility manager.
624 TouchPoint point( 0, state, (float)touchX, (float)touchY );
625 ret = accessibilityAdaptor.HandleActionScrollEvent(point, accessActionInfo.timeStamp);
629 case Dali::Extension::Internal::ACCESS_ACTION_UP:
631 ret = accessibilityAdaptor.HandleActionUpEvent();
635 case Dali::Extension::Internal::ACCESS_ACTION_DOWN:
637 ret = accessibilityAdaptor.HandleActionDownEvent();
641 case Dali::Extension::Internal::ACCESS_ACTION_BACK:
644 DALI_LOG_WARNING("[%s:%d]\n", __FUNCTION__, __LINE__);
652 DALI_LOG_WARNING("[%s:%d]\n", __FUNCTION__, __LINE__);
655 DALI_LOG_INFO(gEvasPluginLogFilter, Debug::General, "[%s:%d] [action : %d] focus manager returns %s\n", __FUNCTION__, __LINE__, (int)(actionType), ret?"TRUE":"FALSE");
660 } // namespace Internal
662 } // namespace Extension