2 * Copyright (c) 2020 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 <dali/internal/window-system/common/gl-window-impl.h>
22 #include <dali/integration-api/core.h>
23 #include <dali/devel-api/adaptor-framework/orientation.h>
24 #include <dali/devel-api/adaptor-framework/gl-window.h>
25 #include <dali/integration-api/events/touch-integ.h>
26 #include <dali/integration-api/events/key-event-integ.h>
27 #include <dali/devel-api/events/key-event-devel.h>
30 #include <dali/internal/window-system/common/event-handler.h>
31 #include <dali/internal/window-system/common/orientation-impl.h>
32 #include <dali/internal/window-system/common/window-factory.h>
33 #include <dali/internal/window-system/common/window-base.h>
34 #include <dali/internal/window-system/common/window-system.h>
35 #include <dali/internal/window-system/common/window-impl.h>
36 #include <dali/internal/window-system/common/window-render-surface.h>
37 #include <dali/internal/window-system/common/window-visibility-observer.h>
38 #include <dali/internal/graphics/gles/egl-graphics-factory.h>
39 #include <dali/internal/window-system/common/display-utils.h>
50 const int MINIMUM_DIMENSION_CHANGE( 1 );
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gWindowLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_WINDOW" );
56 } // unnamed namespace
58 GlWindow* GlWindow::New( const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent )
60 GlWindow* window = new GlWindow();
61 window->mIsTransparent = isTransparent;
62 window->Initialize( positionSize, name, className );
69 mEventHandler( nullptr ),
71 mColorDepth( COLOR_DEPTH_24 ),
72 mIsTransparent( false ),
73 mIsFocusAcceptable( false ),
75 mOpaqueState( false ),
76 mResizeEnabled( false ),
79 mIsWindowRotated( false ),
83 mTotalRotationAngle( 0 ),
84 mWindowRotationAngle( 0 ),
85 mScreenRotationAngle( 0 ),
86 mOrientationMode( 0 ),
89 mNativeWindowId( -1 ),
94 mVisibilityChangedSignal(),
96 mGLRenderFrameCallback( 0 ),
97 mGLTerminateCallback( 0 ),
98 mGLRenderCallback( nullptr ),
99 mEGLSurface( nullptr ),
100 mEGLContext( nullptr ),
101 mGLESVersion( Dali::GlWindow::GlesVersion::VERSION_3_0 ),
102 mInitCallback( false ),
105 mIsEGLInitialize( false ),
110 GlWindow::~GlWindow()
114 mEventHandler->RemoveObserver( *this );
117 if( Dali::Adaptor::IsAvailable() && mGLRenderCallback )
119 Dali::Adaptor::Get().RemoveIdle( mGLRenderCallback );
122 if( mGLTerminateCallback )
124 mGLTerminateCallback();
127 if( mIsEGLInitialize )
129 EglGraphics *eglGraphics = static_cast<EglGraphics*>( mGraphics );
130 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
134 eglImpl.DestroySurface( mEGLSurface );
135 mEGLSurface = nullptr;
140 eglImpl.DestroyContext( mEGLContext );
141 mEGLContext = nullptr;
146 void GlWindow::Initialize( const PositionSize& positionSize, const std::string& name, const std::string& className )
148 int screenWidth, screenHeight;
150 mPositionSize = positionSize;
151 WindowSystem::GetScreenSize( screenWidth, screenHeight );
152 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
156 mPositionSize.width = screenWidth;
157 mPositionSize.height = screenHeight;
160 if( screenWidth > screenHeight )
162 mOrientationMode = 1; // Default mode is landscape
166 mOrientationMode = 0; // Default mode is portrate
169 // Create a window base
170 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
172 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mIsTransparent ? true : false ) );
173 mWindowBase->IconifyChangedSignal().Connect( this, &GlWindow::OnIconifyChanged );
174 mWindowBase->FocusChangedSignal().Connect( this, &GlWindow::OnFocusChanged );
176 if( Dali::Adaptor::IsAvailable() )
181 if( !mPositionSize.IsEmpty() )
183 AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
184 mResizeEnabled = true;
191 mColorDepth = COLOR_DEPTH_32;
195 mColorDepth = COLOR_DEPTH_24;
198 SetClass( name, className );
201 mNativeWindowId = mWindowBase->GetNativeWindowId();
204 void GlWindow::SetEventHandler()
206 mEventHandler = EventHandlerPtr( new EventHandler( mWindowBase.get(), *this ) );
207 mEventHandler->AddObserver( *this );
210 void GlWindow::SetClass( const std::string& name, const std::string className )
213 mClassName = className;
214 mWindowBase->SetClass( name, className );
217 void GlWindow::SetEglConfig( bool depth, bool stencil, int msaa, Dali::GlWindow::GlesVersion version )
223 mGLESVersion = version;
225 InitializeGraphics();
228 void GlWindow::Raise()
230 mWindowBase->Raise();
231 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Raise() \n", this, mNativeWindowId );
234 void GlWindow::Lower()
236 mWindowBase->Lower();
237 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Lower() \n", this, mNativeWindowId );
240 void GlWindow::Activate()
242 mWindowBase->Activate();
243 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Activate() \n", this, mNativeWindowId );
246 void GlWindow::Show()
254 Dali::GlWindow handle( this );
255 mVisibilityChangedSignal.Emit( handle, true );
260 mEventHandler->Resume();
263 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Show(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
266 void GlWindow::Hide()
274 Dali::GlWindow handle( this );
275 mVisibilityChangedSignal.Emit( handle, false );
280 mEventHandler->Pause();
283 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Hide(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
286 unsigned int GlWindow::GetSupportedAuxiliaryHintCount() const
288 return mWindowBase->GetSupportedAuxiliaryHintCount();
291 std::string GlWindow::GetSupportedAuxiliaryHint( unsigned int index ) const
293 return mWindowBase->GetSupportedAuxiliaryHint( index );
296 unsigned int GlWindow::AddAuxiliaryHint( const std::string& hint, const std::string& value )
298 return mWindowBase->AddAuxiliaryHint( hint, value );
301 bool GlWindow::RemoveAuxiliaryHint( unsigned int id )
303 return mWindowBase->RemoveAuxiliaryHint( id );
306 bool GlWindow::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
308 return mWindowBase->SetAuxiliaryHintValue( id, value );
311 std::string GlWindow::GetAuxiliaryHintValue( unsigned int id ) const
313 return mWindowBase->GetAuxiliaryHintValue( id );
316 unsigned int GlWindow::GetAuxiliaryHintId( const std::string& hint ) const
318 return mWindowBase->GetAuxiliaryHintId( hint );
321 void GlWindow::SetInputRegion( const Rect< int >& inputRegion )
323 mWindowBase->SetInputRegion( inputRegion );
325 DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "GlWindow::SetInputRegion: x = %d, y = %d, w = %d, h = %d\n", inputRegion.x, inputRegion.y, inputRegion.width, inputRegion.height );
328 void GlWindow::SetOpaqueState( bool opaque )
330 mOpaqueState = opaque;
332 mWindowBase->SetOpaqueState( opaque );
334 DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "GlWindow::SetOpaqueState: opaque = %d\n", opaque );
337 bool GlWindow::IsOpaqueState() const
342 void GlWindow::SetPositionSize( PositionSize positionSize )
344 if( !mResizeEnabled )
346 AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
347 mResizeEnabled = true;
350 bool needToMove = false;
351 bool needToResize = false;
354 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
355 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
361 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
362 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
371 mWindowBase->MoveResize( positionSize );
375 mWindowBase->Resize( positionSize );
377 mPositionSize = positionSize;
383 mWindowBase->Move( positionSize );
384 mPositionSize = positionSize;
388 // If window's size or position is changed, the signal will be emitted to user.
389 if( ( needToMove ) || ( needToResize ) )
391 Uint16Pair newSize( mPositionSize.width, mPositionSize.height );
392 Dali::GlWindow handle( this );
393 mResizeSignal.Emit( newSize );
397 PositionSize GlWindow::GetPositionSize() const
399 PositionSize positionSize( mPositionSize );
400 if( mTotalRotationAngle == 90 || mTotalRotationAngle == 270 )
402 positionSize.height = mPositionSize.width;
403 positionSize.width = mPositionSize.height;
409 void GlWindow::OnIconifyChanged( bool iconified )
417 Dali::GlWindow handle( this );
418 mVisibilityChangedSignal.Emit( handle, false );
423 mEventHandler->Pause();
426 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Iconified: visible = %d\n", this, mNativeWindowId, mVisible );
434 Dali::GlWindow handle( this );
435 mVisibilityChangedSignal.Emit( handle, true );
440 mEventHandler->Resume();
443 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Deiconified: visible = %d\n", this, mNativeWindowId, mVisible );
447 void GlWindow::OnFocusChanged( bool focusIn )
449 Dali::GlWindow handle( this );
450 mFocusChangeSignal.Emit( handle, focusIn );
453 void GlWindow::OnOutputTransformed()
455 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
456 if( screenRotationAngle != mScreenRotationAngle )
458 mScreenRotationAngle = screenRotationAngle;
459 mTotalRotationAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
461 if( mTotalRotationAngle == 90 || mTotalRotationAngle == 270 )
463 mWindowWidth = mPositionSize.height;
464 mWindowHeight = mPositionSize.width;
468 mWindowWidth = mPositionSize.width;
469 mWindowHeight = mPositionSize.height;
472 // Emit Resize signal
473 Dali::GlWindow handle( this );
474 mResizeSignal.Emit( Dali::Uint16Pair( mWindowWidth, mWindowHeight ) );
478 void GlWindow::OnTouchPoint( Dali::Integration::Point& point, int timeStamp )
480 PointState::Type state = point.GetState();
482 if( state == PointState::DOWN )
487 if( state == PointState::UP )
492 if( !mIsTouched && state == PointState::MOTION )
497 RecalculateTouchPosition( point );
498 Dali::TouchEvent touchEvent = Dali::Integration::NewTouchEvent( timeStamp, point );
499 Dali::GlWindow handle( this );
500 mTouchedSignal.Emit( touchEvent );
503 void GlWindow::OnWheelEvent( Dali::Integration::WheelEvent& wheelEvent )
506 //FeedWheelEvent( wheelEvent );
509 void GlWindow::OnKeyEvent( Dali::Integration::KeyEvent& keyEvent )
511 Dali::KeyEvent event = Dali::DevelKeyEvent::New( keyEvent.keyName, keyEvent.logicalKey, keyEvent.keyString, keyEvent.keyCode,
512 keyEvent.keyModifier, keyEvent.time, static_cast<Dali::KeyEvent::State>(keyEvent.state),
513 keyEvent.compose, keyEvent.deviceName, keyEvent.deviceClass, keyEvent.deviceSubclass );
514 Dali::GlWindow handle( this );
515 mKeyEventSignal.Emit( event );
518 void GlWindow::OnRotation( const RotationEvent& rotation )
520 mWindowRotationAngle = rotation.angle;
521 mTotalRotationAngle = ( mWindowRotationAngle + mScreenRotationAngle ) % 360;
522 if( mTotalRotationAngle == 90 || mTotalRotationAngle == 270 )
524 mWindowWidth = mPositionSize.height;
525 mWindowHeight = mPositionSize.width;
529 mWindowWidth = mPositionSize.width;
530 mWindowHeight = mPositionSize.height;
534 mIsWindowRotated = true;
535 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), OnRotation(): resize signal emit [%d x %d]\n", this, mNativeWindowId, mWindowWidth, mWindowHeight );
537 // Emit Resize signal
538 Dali::GlWindow handle( this );
539 mResizeSignal.Emit( Dali::Uint16Pair( mWindowWidth, mWindowHeight ) );
542 void GlWindow::RecalculateTouchPosition( Integration::Point& point )
544 Vector2 position = point.GetScreenPosition();
545 Vector2 convertedPosition;
547 switch( mTotalRotationAngle )
551 convertedPosition.x = static_cast<float>( mWindowWidth ) - position.y;
552 convertedPosition.y = position.x;
557 convertedPosition.x = static_cast<float>( mWindowWidth ) - position.x;
558 convertedPosition.y = static_cast<float>( mWindowHeight ) - position.y;
563 convertedPosition.x = position.y;
564 convertedPosition.y = static_cast<float>( mWindowHeight ) - position.x;
569 convertedPosition = position;
574 point.SetScreenPosition( convertedPosition );
577 void GlWindow::SetAvailableAnlges( const std::vector< int >& angles )
579 if( angles.size() > 4 )
581 DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::SetAvailableAnlges: Invalid vector size! [%d]\n", angles.size() );
585 mWindowBase->SetAvailableAnlges( angles );
588 bool GlWindow::IsOrientationAvailable( Dali::GlWindow::GlWindowOrientation orientation ) const
590 if( orientation <= Dali::GlWindow::GlWindowOrientation::NO_ORIENTATION_PREFERENCE
591 || orientation > Dali::GlWindow::GlWindowOrientation::LANDSCAPE_INVERSE )
593 DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::IsOrientationAvailable: Invalid input orientation [%d]\n", orientation );
599 int GlWindow::ConvertToAngle( Dali::GlWindow::GlWindowOrientation orientation )
601 int convertAngle = 0;
602 if ( mOrientationMode == 0 )
604 convertAngle = ( static_cast< int >( orientation ) ) * 90;
606 else if( mOrientationMode == 1)
608 switch( orientation )
610 case Dali::GlWindow::GlWindowOrientation::LANDSCAPE:
615 case Dali::GlWindow::GlWindowOrientation::PORTRAIT:
620 case Dali::GlWindow::GlWindowOrientation::LANDSCAPE_INVERSE:
625 case Dali::GlWindow::GlWindowOrientation::PORTRAIT_INVERSE:
630 case Dali::GlWindow::GlWindowOrientation::NO_ORIENTATION_PREFERENCE:
640 Dali::GlWindow::GlWindowOrientation GlWindow::ConvertToOrientation( int angle ) const
642 Dali::GlWindow::GlWindowOrientation orientation = Dali::GlWindow::GlWindowOrientation::NO_ORIENTATION_PREFERENCE;
643 if ( mOrientationMode == 0 ) // Portrate mode
645 orientation = static_cast< Dali::GlWindow::GlWindowOrientation >( angle / 90 );
647 else if( mOrientationMode == 1 ) // Landscape mode
653 orientation = Dali::GlWindow::GlWindowOrientation::LANDSCAPE;
658 orientation = Dali::GlWindow::GlWindowOrientation::PORTRAIT;
663 orientation = Dali::GlWindow::GlWindowOrientation::LANDSCAPE_INVERSE;
668 orientation = Dali::GlWindow::GlWindowOrientation::PORTRAIT_INVERSE;
673 orientation = Dali::GlWindow::GlWindowOrientation::NO_ORIENTATION_PREFERENCE;
681 Dali::GlWindow::GlWindowOrientation GlWindow::GetCurrentOrientation() const
683 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), GetCurrentOrientation(): %d\n", this, mNativeWindowId, mTotalRotationAngle );
684 return ConvertToOrientation( mTotalRotationAngle );
687 void GlWindow::SetAvailableOrientations( const Dali::Vector< Dali::GlWindow::GlWindowOrientation >& orientations )
689 Dali::Vector<float>::SizeType count = orientations.Count();
690 for( Dali::Vector<float>::SizeType index = 0; index < count; ++index )
692 if( IsOrientationAvailable( orientations[index] ) == false )
694 DALI_LOG_ERROR("Window::SetAvailableRotationAngles, invalid angle: %d\n", orientations[index]);
699 int angle = ConvertToAngle( orientations[index] );
701 for( std::size_t i = 0; i < mAvailableAngles.size(); i++ )
703 if( mAvailableAngles[i] == angle )
712 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), SetAvailableOrientations: %d\n", this, mNativeWindowId, angle );
713 mAvailableAngles.push_back( angle );
716 SetAvailableAnlges( mAvailableAngles );
719 void GlWindow::SetPreferredOrientation( Dali::GlWindow::GlWindowOrientation orientation )
721 if( IsOrientationAvailable( orientation ) == false )
723 DALI_LOG_ERROR( "Window::SetPreferredOrientation, invalid orientation: %d\n", orientation );
726 mPreferredAngle = ConvertToAngle( orientation );
727 DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), SetPreferredOrientation: %d\n", this, mNativeWindowId, mPreferredAngle );
728 mWindowBase->SetPreferredAngle( mPreferredAngle );
731 void GlWindow::SetChild( Dali::Window& child )
733 if( DALI_UNLIKELY( child ) )
735 mChildWindow = child;
736 Internal::Adaptor::Window& windowImpl = Dali::GetImplementation( mChildWindow );
737 WindowRenderSurface* renderSurface = static_cast<WindowRenderSurface*>( windowImpl.GetSurface() );
740 WindowBase* childWindowBase = renderSurface->GetWindowBase();
741 if( childWindowBase )
743 childWindowBase->SetParent( mWindowBase.get() );
749 void GlWindow::RegisterGlCallback( GlInitialize glInit, GlRenderFrame glRenderFrame, GlTerminate glTerminate )
751 if( mIsEGLInitialize == false )
753 InitializeGraphics();
755 mGLInitCallback = glInit;
756 mGLRenderFrameCallback = glRenderFrame;
757 mGLTerminateCallback = glTerminate;
759 mInitCallback = false;
761 if( !mGLRenderCallback )
763 mGLRenderCallback = MakeCallback( this, &GlWindow::RunCallback );
765 if( Dali::Adaptor::IsAvailable() )
767 Dali::Adaptor::Get().AddIdle( mGLRenderCallback, true );
771 DALI_LOG_RELEASE_INFO( "RegisterGlCallback: Adaptor is not avaiable\n" );
777 bool GlWindow::RunCallback()
779 EglGraphics *eglGraphics = static_cast<EglGraphics*>( mGraphics );
780 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
782 eglImpl.MakeContextCurrent( mEGLSurface, mEGLContext );
786 mWindowBase->SetEglWindowBufferTransform( mTotalRotationAngle );
787 if( mIsWindowRotated )
789 mWindowBase->SetEglWindowTransform( mWindowRotationAngle );
796 if( mGLInitCallback )
800 mInitCallback = true;
803 if( mGLRenderFrameCallback )
805 mGLRenderFrameCallback();
808 if( mIsWindowRotated )
810 mWindowBase->WindowRotationCompleted( mWindowRotationAngle, mPositionSize.width, mPositionSize.height );
811 mIsWindowRotated = false;
814 eglImpl.SwapBuffers( mEGLSurface );
819 void GlWindow::RenderOnce()
824 void GlWindow::InitializeGraphics()
826 if( !mIsEGLInitialize )
828 mGraphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
829 EglGraphics *eglGraphics = static_cast<EglGraphics *>(mGraphics);
830 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
832 if( mGLESVersion == Dali::GlWindow::GlesVersion::VERSION_2_0 )
834 eglImpl.SetGlesVersion( 20 );
836 else if( mGLESVersion == Dali::GlWindow::GlesVersion::VERSION_3_0 )
838 eglImpl.SetGlesVersion( 30 );
841 if( eglImpl.ChooseConfig(true, mColorDepth) == false )
843 if( mGLESVersion == Dali::GlWindow::GlesVersion::VERSION_3_0 )
845 DALI_LOG_RELEASE_INFO( "InitializeGraphics: Fail to choose config with GLES30, retry with GLES20\n" );
846 eglImpl.SetGlesVersion( 20 );
847 mGLESVersion = Dali::GlWindow::GlesVersion::VERSION_2_0;
848 if( eglImpl.ChooseConfig(true, mColorDepth) == false )
850 DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
856 DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
860 eglImpl.CreateWindowContext( mEGLContext );
862 // Create the EGL window
863 EGLNativeWindowType window = mWindowBase->CreateEglWindow( mPositionSize.width, mPositionSize.height );
864 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
866 mIsEGLInitialize = true;
870 void GlWindow::OnDamaged( const DamageArea& area )