2 * Copyright (c) 2014 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 "ecore-indicator-impl.h"
25 #include <sys/types.h>
31 #include <dali/public-api/images/native-image.h>
32 #include <dali/public-api/events/touch-event.h>
33 #include <dali/public-api/events/touch-point.h>
34 #include <dali/public-api/common/stage.h>
35 #include <dali/public-api/actors/blending.h>
36 #include <dali/public-api/shader-effects/shader-effect.h>
37 #include <dali/public-api/images/buffer-image.h>
39 #include <dali/integration-api/debug.h>
42 #include <adaptor-impl.h>
43 #include <accessibility-adaptor-impl.h>
44 #include <native-image-source.h>
48 #if defined(DEBUG_ENABLED)
49 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
55 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
56 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
57 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
65 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
66 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
68 #define MAKE_SHADER(A)#A
70 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
71 attribute mediump vec2 aPosition;
72 attribute mediump float aAlpha;
73 varying mediump float vAlpha;
74 uniform mediump mat4 uMvpMatrix;
75 uniform mediump vec3 uSize;
79 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
80 vertexPosition = uMvpMatrix * vertexPosition;
83 gl_Position = vertexPosition;
87 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
88 uniform lowp vec4 uColor;
89 varying mediump float vAlpha;
93 gl_FragColor = uColor;
94 gl_FragColor.a *= vAlpha;
98 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
99 attribute mediump vec2 aPosition;\n
100 varying mediump vec2 vTexCoord;\n
101 uniform mediump mat4 uMvpMatrix;\n
102 uniform mediump vec3 uSize;\n
103 uniform mediump vec4 sTextureRect;\n
107 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
108 vTexCoord = aPosition + vec2(0.5);\n
112 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
113 varying mediump vec2 vTexCoord;\n
114 uniform sampler2D sTexture;\n
118 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
122 Dali::Geometry CreateQuadGeometry()
124 Dali::Property::Map quadVertexFormat;
125 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
126 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
128 const float halfQuadSize = .5f;
129 struct QuadVertex { Dali::Vector2 position; };
130 QuadVertex quadVertexData[4] = {
131 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
132 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
133 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
134 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
135 vertexData.SetData(quadVertexData, 4);
137 Dali::Geometry quad = Dali::Geometry::New();
138 quad.AddVertexBuffer( vertexData );
139 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
143 const float OPAQUE_THRESHOLD(0.99f);
144 const float TRANSPARENT_THRESHOLD(0.05f);
146 // indicator service name
147 const char* INDICATOR_SERVICE_NAME("elm_indicator");
149 // Copied from ecore_evas_extn_engine.h
163 OP_PROFILE_CHANGE_REQUEST,
164 OP_PROFILE_CHANGE_DONE,
181 // Copied from elm_conform.c
183 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
184 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
185 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
186 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
187 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
188 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
200 struct IpcIndicatorDataAnimation
206 struct IpcDataEvMouseUp
209 Evas_Button_Flags flags;
211 unsigned int timestamp;
212 Evas_Event_Flags event_flags;
214 IpcDataEvMouseUp(unsigned long timestamp)
216 flags(EVAS_BUTTON_NONE),
218 timestamp(static_cast<unsigned int>(timestamp)),
219 event_flags(EVAS_EVENT_FLAG_NONE)
224 struct IpcDataEvMouseDown
227 Evas_Button_Flags flags;
229 unsigned int timestamp;
230 Evas_Event_Flags event_flags;
232 IpcDataEvMouseDown(unsigned long timestamp)
234 flags(EVAS_BUTTON_NONE),
236 timestamp(static_cast<unsigned int>(timestamp)),
237 event_flags(EVAS_EVENT_FLAG_NONE)
242 struct IpcDataEvMouseMove
245 Evas_Button_Flags flags;
247 unsigned int timestamp;
248 Evas_Event_Flags event_flags;
250 IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
251 : x(static_cast<Evas_Coord>(touchPoint.local.x)),
252 y(static_cast<Evas_Coord>(touchPoint.local.y)),
253 flags(EVAS_BUTTON_NONE),
255 timestamp(static_cast<unsigned int>(timestamp)),
256 event_flags(EVAS_EVENT_FLAG_NONE)
261 struct IpcDataEvMouseOut
263 unsigned int timestamp;
265 Evas_Event_Flags event_flags;
267 IpcDataEvMouseOut(unsigned long timestamp)
268 : timestamp(static_cast<unsigned int>(timestamp)),
270 event_flags(EVAS_EVENT_FLAG_NONE)
275 } // anonymous namespace
284 #if defined(DEBUG_ENABLED)
285 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
289 Indicator::LockFile::LockFile(const std::string filename)
290 : mFilename(filename),
293 mFileDescriptor = open(filename.c_str(), O_RDWR);
294 if( mFileDescriptor == -1 )
298 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
302 Indicator::LockFile::~LockFile()
304 // Closing file descriptor also unlocks file.
305 close( mFileDescriptor );
308 bool Indicator::LockFile::Lock()
310 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
313 if( mFileDescriptor > 0 )
315 if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
323 // file descriptor is no longer valid or not writable
326 DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
334 void Indicator::LockFile::Unlock()
336 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
337 if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
341 // file descriptor is no longer valid or not writable
344 DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
349 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
351 bool error = mErrorThrown;
352 mErrorThrown = false;
356 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
357 : mLockFile(lockFile),
362 mLocked = mLockFile->Lock();
366 Indicator::ScopedLock::~ScopedLock()
374 bool Indicator::ScopedLock::IsLocked()
379 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
381 mGestureDetected( false ),
383 mOpacityMode( Dali::Window::OPAQUE ),
384 mState( DISCONNECTED ),
386 mServerConnection( NULL ),
387 mObserver( observer ),
388 mOrientation( orientation ),
391 mVisible( Dali::Window::INVISIBLE ),
393 mIsAnimationPlaying( false ),
394 mCurrentSharedFile( 0 ),
395 mBackgroundVisible( false )
397 mIndicatorContentActor = Dali::Actor::New();
398 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
399 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
401 // Indicator image handles the touch event including "leave"
402 mIndicatorContentActor.SetLeaveRequired( true );
403 mIndicatorContentActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
404 mIndicatorContentActor.SetColor( Color::BLACK );
406 mIndicatorActor = Dali::Actor::New();
407 mIndicatorActor.Add( mIndicatorContentActor );
409 // Event handler to find out flick down gesture
410 mEventActor = Dali::Actor::New();
411 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
412 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
413 mIndicatorActor.Add( mEventActor );
415 // Attach pan gesture to find flick down during hiding.
416 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
417 // since it consumes the pan gesture in advance.
418 mPanDetector = Dali::PanGestureDetector::New();
419 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
420 mPanDetector.Attach( mEventActor );
424 // register indicator to accessibility adaptor
425 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
426 if(accessibilityAdaptor)
428 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
430 // hide the indicator by default
431 mIndicatorActor.SetVisible( false );
434 Indicator::~Indicator()
438 mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
443 void Indicator::SetAdaptor(Adaptor* adaptor)
446 mIndicatorBuffer->SetAdaptor( adaptor );
449 Dali::Actor Indicator::GetActor()
451 return mIndicatorActor;
454 void Indicator::Open( Dali::Window::WindowOrientation orientation )
456 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
458 // Calls from Window should be set up to ensure we are in a
459 // disconnected state before opening a second time.
460 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
462 mOrientation = orientation;
466 // Change background visibility depending on orientation
467 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
469 if( mBackgroundRenderer )
471 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
472 mBackgroundVisible = false;
477 SetOpacityMode( mOpacityMode );
481 void Indicator::Close()
483 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
485 if( mState == CONNECTED )
488 if( mObserver != NULL )
490 mObserver->IndicatorClosed( this );
494 Dali::Texture emptyTexture;
495 SetForegroundImage( emptyTexture );
498 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
502 Dali::Geometry geometry = CreateBackgroundGeometry();
505 if( mBackgroundRenderer )
507 if( mBackgroundRenderer.GetGeometry() != geometry )
509 mBackgroundRenderer.SetGeometry( geometry );
514 if( !mBackgroundShader )
516 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
519 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
522 if( !mBackgroundVisible )
524 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
525 mBackgroundVisible = true;
528 else if( mBackgroundRenderer )
530 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
531 mBackgroundVisible = false;
535 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
537 if ( visibleMode != mVisible || forceUpdate )
539 // If we were previously hidden, then we should update the image data before we display the indicator
540 if ( mVisible == Dali::Window::INVISIBLE )
542 UpdateImageData( mCurrentSharedFile );
544 if ( visibleMode != Dali::Window::INVISIBLE )
546 mIndicatorActor.SetVisible( true );
549 mVisible = visibleMode;
551 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
553 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
556 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
558 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
561 ShowIndicator( KEEP_SHOWING );
566 ShowIndicator( HIDE_NOW );
572 bool Indicator::IsConnected()
574 return ( mState == CONNECTED );
577 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
581 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
589 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
591 if( mServerConnection )
593 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
595 // Send touch event to indicator server when indicator is showing
596 if( CheckVisibleState() || mIsShowing )
598 switch( touchPoint.state )
600 case Dali::PointState::DOWN:
602 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
603 IpcDataEvMouseDown ipcDown( touchEvent.time );
604 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
605 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
607 if( mVisible == Dali::Window::AUTO )
609 // Stop hiding indicator
610 ShowIndicator( KEEP_SHOWING );
615 case Dali::PointState::MOTION:
617 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
618 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
622 case Dali::PointState::UP:
624 IpcDataEvMouseUp ipcUp( touchEvent.time );
625 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
627 if( mVisible == Dali::Window::AUTO )
630 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
635 case Dali::TouchPoint::Leave:
637 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
638 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
639 IpcDataEvMouseUp ipcOut( touchEvent.time );
640 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
655 bool Indicator::Connect()
657 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
659 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
661 bool connected = false;
663 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
664 if( mServerConnection )
666 connected = mServerConnection->IsConnected();
669 delete mServerConnection;
670 mServerConnection = NULL;
676 StartReconnectionTimer();
686 void Indicator::StartReconnectionTimer()
688 if( ! mReconnectTimer )
690 mReconnectTimer = Dali::Timer::New(1000);
691 mConnection.DisconnectAll();
692 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
694 mReconnectTimer.Start();
697 bool Indicator::OnReconnectTimer()
701 if( mState == DISCONNECTED )
712 void Indicator::Disconnect()
714 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
716 mState = DISCONNECTED;
718 delete mServerConnection;
719 mServerConnection = NULL;
721 ClearSharedFileInfo();
724 void Indicator::Resize( int width, int height )
735 if( mImageWidth != width || mImageHeight != height )
738 mImageHeight = height;
740 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
741 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
742 mEventActor.SetSize(mImageWidth, mImageHeight);
746 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
748 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
750 // epcEvent->ref == w
751 // epcEvent->ref_to == h
752 // epcEvent->response == buffer num
753 // epcEvent->data = lockfile + nul byte
755 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
756 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
758 int n = epcEvent->response;
760 if( n >= 0 && n < SHARED_FILE_NUMBER )
762 mCurrentSharedFile = n;
764 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
765 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
767 mSharedFileInfo[n].mLockFileName.clear();
769 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
771 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
772 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
777 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
779 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
781 // epcEvent->ref == shm id
782 // epcEvent->ref_to == shm num
783 // epcEvent->response == buffer num
784 // epcEvent->data = shm ref string + nul byte
786 if ( (epcEvent->data) &&
787 (epcEvent->size > 0) &&
788 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
790 int n = epcEvent->response;
792 if( n >= 0 && n < SHARED_FILE_NUMBER )
794 mCurrentSharedFile = n;
796 mSharedFileInfo[n].mSharedFileName.clear();
798 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
800 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
801 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
803 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
804 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
809 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
811 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
813 // epcEvent->ref == alpha
814 // epcEvent->ref_to == sys
815 // epcEvent->response == buffer num
817 int n = epcEvent->response;
819 if( n >= 0 && n < SHARED_FILE_NUMBER )
821 mCurrentSharedFile = n;
823 delete mSharedFileInfo[n].mSharedFile;
824 mSharedFileInfo[n].mSharedFile = NULL;
826 delete mSharedFileInfo[n].mLock;
827 mSharedFileInfo[n].mLock = NULL;
829 std::stringstream sharedFileID;
830 std::stringstream sharedFileNumber;
832 sharedFileID << mSharedFileInfo[n].mSharedFileID;
833 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
835 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
837 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
839 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
840 if( mSharedFileInfo[n].mSharedFile != NULL )
842 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
843 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
845 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
850 if( CheckVisibleState() )
852 // set default indicator type (enable the quick panel)
853 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
857 // set default indicator type (disable the quick panel)
858 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
861 SetVisible(mVisible, true);
866 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
868 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
870 // epcEvent->ref == w
871 // epcEvent->ref_to == h
872 // epcEvent->response == alpha
873 // epcEvent->data = pixmap id
875 if( ( epcEvent->data ) &&
876 (epcEvent->size >= (int)sizeof(PixmapId)) )
878 ClearSharedFileInfo();
880 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
882 mImageWidth = epcEvent->ref;
883 mImageHeight = epcEvent->ref_to;
885 mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
886 CreateNewPixmapImage();
888 if( CheckVisibleState() )
890 // set default indicator type (enable the quick panel)
891 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
895 // set default indicator type (disable the quick panel)
896 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
899 SetVisible(mVisible, true);
904 void Indicator::UpdateImageData( int bufferNumber )
906 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
908 if( mState == CONNECTED && mVisible )
912 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
913 CopyToBuffer( bufferNumber );
919 mAdaptor->RequestUpdateOnce();
925 bool Indicator::CopyToBuffer( int bufferNumber )
927 bool success = false;
929 if( mSharedFileInfo[bufferNumber].mLock )
931 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
932 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
936 else if( scopedLock.IsLocked() )
938 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
939 size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
941 if( mIndicatorBuffer->UpdatePixels( src, size ) )
943 mAdaptor->RequestUpdateOnce();
952 void Indicator::CreateNewPixmapImage()
954 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
955 Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
957 if( nativeImageSource )
959 Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
960 SetForegroundImage( texture );
961 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
962 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
963 mEventActor.SetSize( mImageWidth, mImageHeight );
967 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
969 if( mObserver != NULL )
971 mObserver->IndicatorClosed( this );
973 // Don't do connection in this callback - strange things happen!
974 StartReconnectionTimer();
978 void Indicator::CreateNewImage( int bufferNumber )
980 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
981 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
982 bool success = false;
984 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
986 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
989 SetForegroundImage( texture );
996 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
998 if( mObserver != NULL )
1000 mObserver->IndicatorClosed( this );
1002 // Don't do connection in this callback - strange things happen!
1003 StartReconnectionTimer();
1007 Dali::Geometry Indicator::CreateBackgroundGeometry()
1009 switch( mOpacityMode )
1011 case Dali::Window::TRANSLUCENT:
1012 if( !mTranslucentGeometry )
1014 // Construct 5 interval mesh
1028 struct BackgroundVertex
1034 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1035 BackgroundVertex vertices[ numVertices ];
1038 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1039 BackgroundVertex* currentVertex = vertices;
1040 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1042 currentVertex->mPosition = Vector2( -0.5f, d );
1043 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1046 currentVertex->mPosition = Vector2( 0.5f, d );
1047 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1052 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1053 unsigned short indices[ numIndices ];
1055 unsigned short* currentIndex = indices;
1056 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1058 *currentIndex++ = (2 * y);
1059 *currentIndex++ = (2 * y) + 3;
1060 *currentIndex++ = (2 * y) + 1;
1062 *currentIndex++ = (2 * y);
1063 *currentIndex++ = (2 * y) + 2;
1064 *currentIndex++ = (2 * y) + 3;
1067 Dali::Property::Map vertexFormat;
1068 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1069 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1070 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1071 vertexPropertyBuffer.SetData( vertices, numVertices );
1073 // Create the geometry object
1074 mTranslucentGeometry = Dali::Geometry::New();
1075 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1076 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1079 return mTranslucentGeometry;
1080 case Dali::Window::OPAQUE:
1082 if( !mSolidGeometry )
1085 struct BackgroundVertex
1091 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1092 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1095 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1097 Dali::Property::Map vertexFormat;
1098 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1099 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1100 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1101 vertexPropertyBuffer.SetData( vertices, 4 );
1104 // Create the geometry object
1105 mSolidGeometry = Dali::Geometry::New();
1106 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1107 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1110 return mSolidGeometry;
1111 case Dali::Window::TRANSPARENT:
1115 return Dali::Geometry();
1118 void Indicator::SetForegroundImage( Dali::Texture texture )
1120 if( !mForegroundRenderer && texture )
1123 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1125 // Create renderer from geometry and material
1126 Dali::Geometry quad = CreateQuadGeometry();
1127 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1128 // Make sure the foreground stays in front of the background
1129 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1131 // Set blend function
1132 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1133 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1134 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1135 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1137 // Create a texture-set and add to renderer
1139 Dali::TextureSet textureSet = Dali::TextureSet::New();
1140 textureSet.SetTexture( 0u, texture );
1141 mForegroundRenderer.SetTextures( textureSet );
1143 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1145 else if( mForegroundRenderer )
1147 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1148 textureSet.SetTexture( 0u, texture );
1151 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1153 Resize( texture.GetWidth(), texture.GetHeight() );
1157 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1159 if( mObserver != NULL )
1161 mObserver->IndicatorTypeChanged( indicatorType );
1165 void Indicator::DataReceived( void* event )
1167 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1168 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1170 switch( epcEvent->minor )
1174 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1177 mAdaptor->RequestUpdateOnce();
1181 case OP_UPDATE_DONE:
1183 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1184 // epcEvent->response == display buffer #
1185 UpdateImageData( epcEvent->response );
1190 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1191 SetSharedImageInfo( epcEvent );
1196 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1197 SetLockFileInfo( epcEvent );
1202 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1203 LoadSharedImage( epcEvent );
1208 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1210 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1212 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1213 Resize( newSize->w, newSize->h );
1219 int msgDomain = epcEvent->ref;
1220 int msgId = epcEvent->ref_to;
1222 void *msgData = NULL;
1223 int msgDataSize = 0;
1224 msgData = epcEvent->data;
1225 msgDataSize = epcEvent->size;
1227 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1229 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1233 case MSG_ID_INDICATOR_TYPE:
1235 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1236 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1237 OnIndicatorTypeChanged( *indicatorType );
1241 case MSG_ID_INDICATOR_START_ANIMATION:
1243 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1245 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1247 DALI_LOG_ERROR("Message data is incorrect\n");
1251 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1253 if(!CheckVisibleState())
1255 ShowIndicator( animData->duration /* n sec */ );
1267 void Indicator::ConnectionClosed()
1269 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1271 // Will get this callback if the server connection failed to start up.
1272 delete mServerConnection;
1273 mServerConnection = NULL;
1274 mState = DISCONNECTED;
1276 // Attempt to re-connect
1280 bool Indicator::CheckVisibleState()
1282 if( mOrientation == Dali::Window::LANDSCAPE
1283 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1284 || (mVisible != Dali::Window::VISIBLE) )
1292 void Indicator::ClearSharedFileInfo()
1294 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1296 delete mSharedFileInfo[i].mLock;
1297 mSharedFileInfo[i].mLock = NULL;
1299 delete mSharedFileInfo[i].mSharedFile;
1300 mSharedFileInfo[i].mSharedFile = NULL;
1302 mSharedFileInfo[i].mLockFileName.clear();
1303 mSharedFileInfo[i].mSharedFileName.clear();
1308 * duration can be this
1312 * KEEP_SHOWING = -1,
1316 void Indicator::ShowIndicator(float duration)
1318 if( !mIndicatorAnimation )
1320 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1321 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1324 if(mIsShowing && !EqualsZero(duration))
1326 // If need to show during showing, do nothing.
1327 // In 2nd phase (below) will update timer
1329 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1331 // If need to hide during hiding or hidden already, do nothing
1335 if( EqualsZero(duration) )
1337 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1341 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1345 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1349 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1352 mIndicatorAnimation.Play();
1353 mIsAnimationPlaying = true;
1360 mShowTimer = Dali::Timer::New(1000 * duration);
1361 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1363 mShowTimer.SetInterval(1000* duration);
1366 if( mVisible == Dali::Window::AUTO )
1368 // check the stage touch
1369 Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1374 if(mShowTimer && mShowTimer.IsRunning())
1379 if( mVisible == Dali::Window::AUTO )
1381 // check the stage touch
1382 Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1387 bool Indicator::OnShowTimer()
1389 // after time up, hide indicator
1390 ShowIndicator( HIDE_NOW );
1395 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1397 mIsAnimationPlaying = false;
1398 // once animation is finished and indicator is hidden, take it off stage
1401 if( mObserver != NULL )
1403 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1408 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1410 if( mServerConnection )
1412 switch( gesture.state )
1414 case Gesture::Started:
1416 mGestureDetected = false;
1418 // The gesture position is the current position after it has moved by the displacement.
1419 // We want to reference the original position.
1420 mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1423 // No break, Fall through
1424 case Gesture::Continuing:
1426 if( mVisible == Dali::Window::AUTO && !mIsShowing )
1428 // Only take one touch point
1429 if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1431 mGestureDeltaY += gesture.displacement.y;
1433 if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1435 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1436 mGestureDetected = true;
1444 case Gesture::Finished:
1445 case Gesture::Cancelled:
1447 // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1448 if( mVisible == Dali::Window::AUTO && mIsShowing )
1450 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1462 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1464 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1466 // when stage is touched while indicator is showing temporary, hide it
1467 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1469 switch( touchPoint.state )
1471 case Dali::PointState::DOWN:
1473 ShowIndicator( HIDE_NOW );