2 * Copyright (c) 2018 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/tizen-wayland/indicator-impl-ecore-wl.h>
22 // Ecore is littered with C style cast
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wold-style-cast"
29 #include <Ecore_Wl2.h>
31 #include <Ecore_Wayland.h>
34 #include <sys/types.h>
39 #include <dali/public-api/images/native-image.h>
40 #include <dali/public-api/events/touch-point.h>
41 #include <dali/public-api/common/stage.h>
42 #include <dali/public-api/images/pixel.h>
44 #include <dali/integration-api/debug.h>
47 #include <dali/internal/adaptor/common/adaptor-impl.h>
48 #include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
49 #include <dali/public-api/adaptor-framework/native-image-source.h>
51 #if defined(DEBUG_ENABLED)
52 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
58 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
59 const float AUTO_INDICATOR_STAY_DURATION( 3.0f ); // 3 seconds
67 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
68 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
70 #define MAKE_SHADER(A)#A
72 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
73 attribute mediump vec2 aPosition;
74 attribute mediump float aAlpha;
75 varying mediump float vAlpha;
76 uniform mediump mat4 uMvpMatrix;
77 uniform mediump vec3 uSize;
81 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
82 vertexPosition = uMvpMatrix * vertexPosition;
85 gl_Position = vertexPosition;
89 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
90 uniform lowp vec4 uColor;
91 varying mediump float vAlpha;
95 gl_FragColor = uColor;
96 gl_FragColor.a *= vAlpha;
100 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
101 attribute mediump vec2 aPosition;\n
102 varying mediump vec2 vTexCoord;\n
103 uniform mediump mat4 uMvpMatrix;\n
104 uniform mediump vec3 uSize;\n
105 uniform mediump vec4 sTextureRect;\n
109 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
110 vTexCoord = aPosition + vec2(0.5);\n
114 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
115 varying mediump vec2 vTexCoord;\n
116 uniform sampler2D sTexture;\n
120 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
124 Dali::Geometry CreateQuadGeometry()
126 Dali::Property::Map quadVertexFormat;
127 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
128 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
130 const float halfQuadSize = .5f;
131 struct QuadVertex { Dali::Vector2 position; };
132 QuadVertex quadVertexData[4] = {
133 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
134 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
135 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
136 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
137 vertexData.SetData(quadVertexData, 4);
139 Dali::Geometry quad = Dali::Geometry::New();
140 quad.AddVertexBuffer( vertexData );
141 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
145 // indicator service name
146 const char* INDICATOR_SERVICE_NAME("elm_indicator");
148 // Copied from ecore_evas_extn_engine.h
162 OP_PROFILE_CHANGE_REQUEST,
163 OP_PROFILE_CHANGE_DONE,
180 // Copied from elm_conform.c
182 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
183 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
184 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
185 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
186 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
187 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
194 struct IpcIndicatorDataAnimation
200 struct IpcDataEvMouseUp
203 Evas_Button_Flags flags;
205 unsigned int timestamp;
206 Evas_Event_Flags event_flags;
208 IpcDataEvMouseUp(unsigned long timestamp)
210 flags(EVAS_BUTTON_NONE),
212 timestamp(static_cast<unsigned int>(timestamp)),
213 event_flags(EVAS_EVENT_FLAG_NONE)
218 struct IpcDataEvMouseDown
221 Evas_Button_Flags flags;
223 unsigned int timestamp;
224 Evas_Event_Flags event_flags;
226 IpcDataEvMouseDown(unsigned long timestamp)
228 flags(EVAS_BUTTON_NONE),
230 timestamp(static_cast<unsigned int>(timestamp)),
231 event_flags(EVAS_EVENT_FLAG_NONE)
236 struct IpcDataEvMouseMove
239 Evas_Button_Flags flags;
241 unsigned int timestamp;
242 Evas_Event_Flags event_flags;
244 IpcDataEvMouseMove(const Dali::Vector2& touchPoint, unsigned long timestamp)
245 : x(static_cast<Evas_Coord>(touchPoint.x)),
246 y(static_cast<Evas_Coord>(touchPoint.y)),
247 flags(EVAS_BUTTON_NONE),
249 timestamp(static_cast<unsigned int>(timestamp)),
250 event_flags(EVAS_EVENT_FLAG_NONE)
255 struct IpcDataEvMouseOut
257 unsigned int timestamp;
259 Evas_Event_Flags event_flags;
261 IpcDataEvMouseOut(unsigned long timestamp)
262 : timestamp(static_cast<unsigned int>(timestamp)),
264 event_flags(EVAS_EVENT_FLAG_NONE)
269 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
271 void SaveIndicatorImage( Dali::NativeImageSourcePtr nativeImageSource )
273 // Save image data to disk in BMP form.
274 static int gFilenameCounter = 0;
275 static const char bmpHeader[] = {
276 0x42, 0x4d, 0x0a, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x7c, 0x00,
278 0xe0, 0x01, 0x00, 0x00, // Width (480)
279 0x1b, 0x00, 0x00, 0x00, // Height ( 27)
280 0x01, 0x00, 0x20, 0x00, 0x03, 0x00,
281 0x00, 0x00, 0x80, 0xca, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
283 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
290 // This is a BMP header with width & height hard-coded in.
291 // The data was first determined by dumping the raw data and inspecting in GIMP, before creating this header data.
292 std::vector<unsigned char> buffer;
295 Dali::Pixel::Format pixelFormat;
296 if( nativeImageSource->GetPixels( buffer, w, h, pixelFormat ) )
298 int imageSize = w * h * 4;
299 std::stringstream fileName;
300 // Give each file an incremental filename.
301 fileName << "/opt/usr/media/Images/out-" << std::setfill( '0' ) << std::setw( 5 ) << gFilenameCounter << ".bmp";
303 std::ofstream outfile( fileName.str().c_str(), std::ofstream::binary );
304 if( outfile.is_open() )
306 DALI_LOG_WARNING( "Saving Indicator Image w:%d, h:%d, %s\n", w, h, fileName.str().c_str() );
308 outfile.write( bmpHeader, sizeof( bmpHeader ) / sizeof( bmpHeader[0] ) ); // Size of the BMP header.
309 outfile.write( (const char*)buffer.data(), imageSize );
315 DALI_LOG_ERROR( "COULD NOT OPEN FOR SAVING: %s\n", fileName.str().c_str() );
322 } // anonymous namespace
331 #if defined(DEBUG_ENABLED)
332 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
335 // Impl to hide EFL implementation.
337 struct IndicatorEcoreWl::Impl
339 enum // operation mode
342 INDICATOR_STAY_WITH_DURATION
348 Impl(IndicatorEcoreWl* indicator)
349 : mIndicator(indicator),
350 mEcoreEventHandler(NULL)
352 #if defined(DALI_PROFILE_MOBILE)
353 #ifdef ECORE_WAYLAND2
354 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL2_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
356 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
358 #endif // DALI_PROFILE_MOBILE
366 if ( mEcoreEventHandler )
368 ecore_event_handler_del(mEcoreEventHandler);
372 static void SetIndicatorVisibility( void* data, int operation )
374 IndicatorEcoreWl::Impl* indicatorImpl((IndicatorEcoreWl::Impl*)data);
376 if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
380 if ( operation == INDICATOR_STAY_WITH_DURATION )
382 // if indicator is not showing, INDICATOR_FLICK_DONE is given
383 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
384 !indicatorImpl->mIndicator->mIsShowing )
386 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
389 else if( operation == INDICATOR_HIDE )
391 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
392 indicatorImpl->mIndicator->mIsShowing )
394 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
399 #if defined(DALI_PROFILE_MOBILE)
401 * Called when the Ecore indicator event is received.
403 static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
405 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
406 return ECORE_CALLBACK_PASS_ON;
408 #endif // DALI_PROFILE_MOBILE
411 IndicatorEcoreWl* mIndicator;
412 Ecore_Event_Handler* mEcoreEventHandler;
415 IndicatorEcoreWl::LockFile::LockFile(const std::string filename)
416 : mFilename(filename),
419 mFileDescriptor = open(filename.c_str(), O_RDWR);
420 if( mFileDescriptor == -1 )
424 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
428 IndicatorEcoreWl::LockFile::~LockFile()
430 // Closing file descriptor also unlocks file.
431 if( mFileDescriptor > 0 )
433 close( mFileDescriptor );
437 bool IndicatorEcoreWl::LockFile::Lock()
439 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
442 if( mFileDescriptor > 0 )
444 struct flock filelock;
446 filelock.l_type = F_RDLCK;
447 filelock.l_whence = SEEK_SET;
448 filelock.l_start = 0;
450 if( fcntl( mFileDescriptor, F_SETLKW, &filelock ) == -1 )
453 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
463 DALI_LOG_ERROR( "### Invalid fd ###\n" );
469 void IndicatorEcoreWl::LockFile::Unlock()
471 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
473 if( mFileDescriptor > 0 )
475 struct flock filelock;
477 filelock.l_type = F_UNLCK;
478 filelock.l_whence = SEEK_SET;
479 filelock.l_start = 0;
481 if (fcntl(mFileDescriptor, F_SETLKW, &filelock) == -1)
484 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
489 bool IndicatorEcoreWl::LockFile::RetrieveAndClearErrorStatus()
491 bool error = mErrorThrown;
492 mErrorThrown = false;
496 IndicatorEcoreWl::ScopedLock::ScopedLock(LockFile* lockFile)
497 : mLockFile(lockFile),
502 mLocked = mLockFile->Lock();
506 IndicatorEcoreWl::ScopedLock::~ScopedLock()
514 bool IndicatorEcoreWl::ScopedLock::IsLocked()
519 IndicatorEcoreWl::IndicatorEcoreWl( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
520 : mConnection( this ),
521 mOpacityMode( Dali::Window::OPAQUE ),
522 mState( DISCONNECTED ),
524 mServerConnection( NULL ),
525 mObserver( observer ),
526 mOrientation( orientation ),
529 mVisible( Dali::Window::INVISIBLE ),
531 mIsAnimationPlaying( false ),
532 mCurrentSharedFile( 0 ),
534 mBackgroundVisible( false ),
537 mIndicatorContentActor = Dali::Actor::New();
538 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
539 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
541 // Indicator image handles the touch event including "leave"
542 mIndicatorContentActor.SetLeaveRequired( true );
543 mIndicatorContentActor.TouchSignal().Connect( this, &IndicatorEcoreWl::OnTouch );
544 mIndicatorContentActor.SetColor( Color::BLACK );
546 mIndicatorActor = Dali::Actor::New();
547 mIndicatorActor.Add( mIndicatorContentActor );
549 // Event handler to find out flick down gesture
550 mEventActor = Dali::Actor::New();
551 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
552 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
553 mIndicatorActor.Add( mEventActor );
555 // Attach pan gesture to find flick down during hiding.
556 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
557 // since it consumes the pan gesture in advance.
558 mPanDetector = Dali::PanGestureDetector::New();
559 mPanDetector.DetectedSignal().Connect( this, &IndicatorEcoreWl::OnPan );
560 mPanDetector.Attach( mEventActor );
564 // register indicator to accessibility adaptor
565 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
566 if(accessibilityAdaptor)
568 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
570 // hide the indicator by default
571 mIndicatorActor.SetVisible( false );
573 // create impl to handle ecore event
574 mImpl = new Impl(this);
577 IndicatorEcoreWl::~IndicatorEcoreWl()
587 mEventActor.TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnTouch );
592 void IndicatorEcoreWl::SetAdaptor(Adaptor* adaptor)
595 mIndicatorBuffer->SetAdaptor( adaptor );
598 Dali::Actor IndicatorEcoreWl::GetActor()
600 return mIndicatorActor;
603 void IndicatorEcoreWl::Open( Dali::Window::WindowOrientation orientation )
605 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
607 // Calls from Window should be set up to ensure we are in a
608 // disconnected state before opening a second time.
609 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
611 mOrientation = orientation;
615 // Change background visibility depending on orientation
616 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
618 if( mBackgroundRenderer )
620 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
621 mBackgroundVisible = false;
626 SetOpacityMode( mOpacityMode );
630 void IndicatorEcoreWl::Close()
632 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
634 if( mState == CONNECTED )
637 if( mObserver != NULL )
639 mObserver->IndicatorClosed( this );
643 Dali::Texture emptyTexture;
644 SetForegroundImage( emptyTexture );
647 void IndicatorEcoreWl::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
651 Dali::Geometry geometry = CreateBackgroundGeometry();
654 if( mBackgroundRenderer )
656 if( mBackgroundRenderer.GetGeometry() != geometry )
658 mBackgroundRenderer.SetGeometry( geometry );
663 if( !mBackgroundShader )
665 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
668 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
671 if( !mBackgroundVisible )
673 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
674 mBackgroundVisible = true;
677 else if( mBackgroundRenderer )
679 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
680 mBackgroundVisible = false;
685 void IndicatorEcoreWl::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
687 if ( visibleMode != mVisible || forceUpdate )
689 // If we were previously hidden, then we should update the image data before we display the indicator
690 if ( mVisible == Dali::Window::INVISIBLE )
692 UpdateImageData( mCurrentSharedFile );
695 if ( visibleMode == Dali::Window::INVISIBLE )
697 if (mServerConnection)
699 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
704 mIndicatorActor.SetVisible( true );
706 if( mServerConnection )
708 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
712 mVisible = visibleMode;
715 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
717 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
720 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
722 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
725 ShowIndicator( KEEP_SHOWING );
730 ShowIndicator( HIDE_NOW );
740 bool IndicatorEcoreWl::IsConnected()
742 return ( mState == CONNECTED );
745 bool IndicatorEcoreWl::SendMessage( int messageDomain, int messageId, const void *data, int size )
749 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
757 bool IndicatorEcoreWl::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
759 if( mServerConnection )
761 // Send touch event to indicator server when indicator is showing
762 if( CheckVisibleState() || mIsShowing )
764 switch( touchData.GetState(0) )
766 case Dali::PointState::DOWN:
768 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
769 IpcDataEvMouseDown ipcDown( touchData.GetTime() );
770 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
771 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
773 if( mVisible == Dali::Window::AUTO )
775 // Stop hiding indicator
776 ShowIndicator( KEEP_SHOWING );
781 case Dali::PointState::MOTION:
783 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
784 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
788 case Dali::PointState::UP:
789 case Dali::PointState::INTERRUPTED:
791 IpcDataEvMouseUp ipcUp( touchData.GetTime() );
792 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
794 if( mVisible == Dali::Window::AUTO )
797 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
802 case Dali::TouchPoint::Leave:
804 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
805 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
806 IpcDataEvMouseUp ipcOut( touchData.GetTime() );
807 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
822 bool IndicatorEcoreWl::Connect()
824 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
826 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
828 bool connected = false;
830 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
831 if( mServerConnection )
833 connected = mServerConnection->IsConnected();
836 delete mServerConnection;
837 mServerConnection = NULL;
843 StartReconnectionTimer();
853 void IndicatorEcoreWl::StartReconnectionTimer()
855 if( ! mReconnectTimer )
857 mReconnectTimer = Dali::Timer::New(1000);
858 mConnection.DisconnectAll();
859 mReconnectTimer.TickSignal().Connect( mConnection, &IndicatorEcoreWl::OnReconnectTimer );
861 mReconnectTimer.Start();
864 bool IndicatorEcoreWl::OnReconnectTimer()
868 if( mState == DISCONNECTED )
879 void IndicatorEcoreWl::Disconnect()
881 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
883 mState = DISCONNECTED;
885 delete mServerConnection;
886 mServerConnection = NULL;
888 ClearSharedFileInfo();
891 void IndicatorEcoreWl::Resize( int width, int height )
902 if( mImageWidth != width || mImageHeight != height )
905 mImageHeight = height;
907 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
908 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
909 mEventActor.SetSize(mImageWidth, mImageHeight);
914 void IndicatorEcoreWl::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
916 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
918 // epcEvent->ref == w
919 // epcEvent->ref_to == h
920 // epcEvent->response == buffer num
921 // epcEvent->data = lockfile + nul byte
923 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
924 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
926 int n = epcEvent->response;
928 if( n >= 0 && n < SHARED_FILE_NUMBER )
930 mCurrentSharedFile = n;
932 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
933 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
935 mSharedFileInfo[n].mLockFileName.clear();
937 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
939 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
940 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
945 void IndicatorEcoreWl::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
947 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
949 // epcEvent->ref == shm id
950 // epcEvent->ref_to == shm num
951 // epcEvent->response == buffer num
952 // epcEvent->data = shm ref string + nul byte
954 if ( (epcEvent->data) &&
955 (epcEvent->size > 0) &&
956 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
958 int n = epcEvent->response;
960 if( n >= 0 && n < SHARED_FILE_NUMBER )
962 mCurrentSharedFile = n;
964 mSharedFileInfo[n].mSharedFileName.clear();
966 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
968 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
969 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
971 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
972 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
977 void IndicatorEcoreWl::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
979 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
981 // epcEvent->ref == alpha
982 // epcEvent->ref_to == sys
983 // epcEvent->response == buffer num
985 int n = epcEvent->response;
987 if( n >= 0 && n < SHARED_FILE_NUMBER )
989 mCurrentSharedFile = n;
991 delete mSharedFileInfo[n].mSharedFile;
992 mSharedFileInfo[n].mSharedFile = NULL;
994 delete mSharedFileInfo[n].mLock;
995 mSharedFileInfo[n].mLock = NULL;
997 std::stringstream sharedFileID;
998 std::stringstream sharedFileNumber;
1000 sharedFileID << mSharedFileInfo[n].mSharedFileID;
1001 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
1003 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1005 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1007 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1008 if( mSharedFileInfo[n].mSharedFile != NULL )
1010 mSharedFileInfo[n].mLock = new IndicatorEcoreWl::LockFile( mSharedFileInfo[n].mLockFileName );
1011 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1013 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1017 CreateNewImage( n );
1024 void IndicatorEcoreWl::UpdateTopMargin()
1026 int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1027 if (mTopMargin != newMargin)
1029 mTopMargin = newMargin;
1030 mAdaptor->IndicatorSizeChanged( mTopMargin );
1034 void IndicatorEcoreWl::UpdateVisibility()
1036 if( CheckVisibleState() )
1038 // set default indicator type (enable the quick panel)
1039 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1043 // set default indicator type (disable the quick panel)
1044 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1049 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1052 SetVisible(mVisible, true);
1055 void IndicatorEcoreWl::UpdateImageData( int bufferNumber )
1057 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1059 if( mState == CONNECTED && mVisible )
1061 // not sure we can skip it when mIsShowing is false
1062 CopyToBuffer( bufferNumber );
1066 bool IndicatorEcoreWl::CopyToBuffer( int bufferNumber )
1068 bool success = false;
1070 if( mSharedFileInfo[bufferNumber].mLock )
1072 IndicatorEcoreWl::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1073 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1077 else if( scopedLock.IsLocked() )
1079 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1080 size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1082 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1084 mAdaptor->RequestUpdateOnce();
1093 void IndicatorEcoreWl::CreateNewImage( int bufferNumber )
1095 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1096 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1097 bool success = false;
1099 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1101 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1104 SetForegroundImage( texture );
1111 DALI_LOG_WARNING("### Cannot create indicator image ###\n");
1115 Dali::Geometry IndicatorEcoreWl::CreateBackgroundGeometry()
1117 switch( mOpacityMode )
1119 case Dali::Window::TRANSLUCENT:
1120 if( !mTranslucentGeometry )
1122 // Construct 5 interval mesh
1136 struct BackgroundVertex
1142 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1143 BackgroundVertex vertices[ numVertices ];
1146 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1147 BackgroundVertex* currentVertex = vertices;
1148 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1150 currentVertex->mPosition = Vector2( -0.5f, d );
1151 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1154 currentVertex->mPosition = Vector2( 0.5f, d );
1155 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1160 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1161 unsigned short indices[ numIndices ];
1163 unsigned short* currentIndex = indices;
1164 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1166 *currentIndex++ = (2 * y);
1167 *currentIndex++ = (2 * y) + 3;
1168 *currentIndex++ = (2 * y) + 1;
1170 *currentIndex++ = (2 * y);
1171 *currentIndex++ = (2 * y) + 2;
1172 *currentIndex++ = (2 * y) + 3;
1175 Dali::Property::Map vertexFormat;
1176 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1177 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1178 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1179 vertexPropertyBuffer.SetData( vertices, numVertices );
1181 // Create the geometry object
1182 mTranslucentGeometry = Dali::Geometry::New();
1183 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1184 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1187 return mTranslucentGeometry;
1188 case Dali::Window::OPAQUE:
1190 if( !mSolidGeometry )
1193 struct BackgroundVertex
1199 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1200 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1203 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1205 Dali::Property::Map vertexFormat;
1206 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1207 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1208 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1209 vertexPropertyBuffer.SetData( vertices, 4 );
1212 // Create the geometry object
1213 mSolidGeometry = Dali::Geometry::New();
1214 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1215 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1218 return mSolidGeometry;
1219 case Dali::Window::TRANSPARENT:
1223 return Dali::Geometry();
1226 void IndicatorEcoreWl::SetForegroundImage( Dali::Texture texture )
1228 if( !mForegroundRenderer && texture )
1231 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1233 // Create renderer from geometry and material
1234 Dali::Geometry quad = CreateQuadGeometry();
1235 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1236 // Make sure the foreground stays in front of the background
1237 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1239 // Set blend function
1240 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1241 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1242 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1243 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1245 // Create a texture-set and add to renderer
1247 Dali::TextureSet textureSet = Dali::TextureSet::New();
1248 textureSet.SetTexture( 0u, texture );
1249 mForegroundRenderer.SetTextures( textureSet );
1251 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1253 else if( mForegroundRenderer )
1255 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1256 textureSet.SetTexture( 0u, texture );
1259 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1261 Resize( texture.GetWidth(), texture.GetHeight() );
1265 void IndicatorEcoreWl::OnIndicatorTypeChanged( Type indicatorType )
1267 if( mObserver != NULL )
1269 mObserver->IndicatorTypeChanged( indicatorType );
1273 void IndicatorEcoreWl::DataReceived( void* event )
1275 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1276 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1278 switch( epcEvent->minor )
1282 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1285 mAdaptor->RequestUpdateOnce();
1289 case OP_UPDATE_DONE:
1291 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1292 // epcEvent->response == display buffer #
1293 UpdateImageData( epcEvent->response );
1298 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1299 SetSharedImageInfo( epcEvent );
1304 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1305 SetLockFileInfo( epcEvent );
1310 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1311 LoadSharedImage( epcEvent );
1316 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1318 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1320 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1321 Resize( newSize->w, newSize->h );
1327 int msgDomain = epcEvent->ref;
1328 int msgId = epcEvent->ref_to;
1330 void *msgData = NULL;
1331 int msgDataSize = 0;
1332 msgData = epcEvent->data;
1333 msgDataSize = epcEvent->size;
1335 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1337 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1341 case MSG_ID_INDICATOR_TYPE:
1343 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1344 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1345 OnIndicatorTypeChanged( *indicatorType );
1349 case MSG_ID_INDICATOR_START_ANIMATION:
1351 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1353 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1355 DALI_LOG_ERROR("Message data is incorrect\n");
1359 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1361 if(!CheckVisibleState())
1363 ShowIndicator( animData->duration /* n sec */ );
1374 void IndicatorEcoreWl::ConnectionClosed()
1376 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1378 // Will get this callback if the server connection failed to start up.
1379 delete mServerConnection;
1380 mServerConnection = NULL;
1381 mState = DISCONNECTED;
1383 // Attempt to re-connect
1387 bool IndicatorEcoreWl::CheckVisibleState()
1389 if( mOrientation == Dali::Window::LANDSCAPE
1390 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1391 || (mVisible == Dali::Window::INVISIBLE)
1392 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1400 void IndicatorEcoreWl::ClearSharedFileInfo()
1402 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1404 delete mSharedFileInfo[i].mLock;
1405 mSharedFileInfo[i].mLock = NULL;
1407 delete mSharedFileInfo[i].mSharedFile;
1408 mSharedFileInfo[i].mSharedFile = NULL;
1410 mSharedFileInfo[i].mLockFileName.clear();
1411 mSharedFileInfo[i].mSharedFileName.clear();
1416 * duration can be this
1420 * KEEP_SHOWING = -1,
1424 void IndicatorEcoreWl::ShowIndicator(float duration)
1426 if( !mIndicatorAnimation )
1428 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1429 mIndicatorAnimation.FinishedSignal().Connect(this, &IndicatorEcoreWl::OnAnimationFinished);
1432 if(mIsShowing && !EqualsZero(duration))
1434 // If need to show during showing, do nothing.
1435 // In 2nd phase (below) will update timer
1437 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1439 // If need to hide during hiding or hidden already, do nothing
1443 mIndicatorAnimation.Clear();
1445 if( EqualsZero(duration) )
1447 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1451 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1455 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1459 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1462 mIndicatorAnimation.Play();
1463 mIsAnimationPlaying = true;
1470 mShowTimer = Dali::Timer::New(1000 * duration);
1471 mShowTimer.TickSignal().Connect(this, &IndicatorEcoreWl::OnShowTimer);
1473 mShowTimer.SetInterval(1000* duration);
1476 if( mVisible == Dali::Window::AUTO )
1478 // check the stage touch
1479 Dali::Stage::GetCurrent().TouchSignal().Connect( this, &IndicatorEcoreWl::OnStageTouch );
1484 if(mShowTimer && mShowTimer.IsRunning())
1489 if( mVisible == Dali::Window::AUTO )
1491 // check the stage touch
1492 Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnStageTouch );
1497 bool IndicatorEcoreWl::OnShowTimer()
1499 // after time up, hide indicator
1500 ShowIndicator( HIDE_NOW );
1505 void IndicatorEcoreWl::OnAnimationFinished(Dali::Animation& animation)
1507 mIsAnimationPlaying = false;
1508 // once animation is finished and indicator is hidden, take it off stage
1509 if( mObserver != NULL )
1511 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1515 void IndicatorEcoreWl::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1517 // Nothing to do, but we still want to consume pan
1520 void IndicatorEcoreWl::OnStageTouch(const Dali::TouchData& touchData)
1522 // when stage is touched while indicator is showing temporary, hide it
1523 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1525 switch( touchData.GetState(0) )
1527 case Dali::PointState::DOWN:
1529 // if touch point is inside the indicator, indicator is not hidden
1530 if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
1532 ShowIndicator( HIDE_NOW );
1549 #pragma GCC diagnostic pop