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"
28 #include <sys/types.h>
34 #include <dali/public-api/images/native-image.h>
35 #include <dali/public-api/events/touch-event.h>
36 #include <dali/public-api/events/touch-point.h>
37 #include <dali/public-api/common/stage.h>
38 #include <dali/public-api/actors/blending.h>
39 #include <dali/public-api/shader-effects/shader-effect.h>
40 #include <dali/public-api/images/buffer-image.h>
42 #include <dali/integration-api/debug.h>
45 #include <adaptor-impl.h>
46 #include <accessibility-adaptor-impl.h>
47 #include <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
60 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
68 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
69 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
71 #define MAKE_SHADER(A)#A
73 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
74 attribute mediump vec2 aPosition;
75 attribute mediump float aAlpha;
76 varying mediump float vAlpha;
77 uniform mediump mat4 uMvpMatrix;
78 uniform mediump vec3 uSize;
82 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
83 vertexPosition = uMvpMatrix * vertexPosition;
86 gl_Position = vertexPosition;
90 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
91 uniform lowp vec4 uColor;
92 varying mediump float vAlpha;
96 gl_FragColor = uColor;
97 gl_FragColor.a *= vAlpha;
101 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
102 attribute mediump vec2 aPosition;\n
103 varying mediump vec2 vTexCoord;\n
104 uniform mediump mat4 uMvpMatrix;\n
105 uniform mediump vec3 uSize;\n
106 uniform mediump vec4 sTextureRect;\n
110 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
111 vTexCoord = aPosition + vec2(0.5);\n
115 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
116 varying mediump vec2 vTexCoord;\n
117 uniform sampler2D sTexture;\n
121 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
125 Dali::Geometry CreateQuadGeometry()
127 Dali::Property::Map quadVertexFormat;
128 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
129 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
131 const float halfQuadSize = .5f;
132 struct QuadVertex { Dali::Vector2 position; };
133 QuadVertex quadVertexData[4] = {
134 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
135 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
136 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
137 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
138 vertexData.SetData(quadVertexData, 4);
140 Dali::Geometry quad = Dali::Geometry::New();
141 quad.AddVertexBuffer( vertexData );
142 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
146 const float OPAQUE_THRESHOLD(0.99f);
147 const float TRANSPARENT_THRESHOLD(0.05f);
149 // indicator service name
150 const char* INDICATOR_SERVICE_NAME("elm_indicator");
152 // Copied from ecore_evas_extn_engine.h
168 OP_PROFILE_CHANGE_REQUEST,
169 OP_PROFILE_CHANGE_DONE,
187 // Copied from elm_conform.c
189 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
190 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
191 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
192 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
193 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
194 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
206 struct IpcIndicatorDataAnimation
212 struct IpcDataEvMouseUp
215 Evas_Button_Flags flags;
217 unsigned int timestamp;
218 Evas_Event_Flags event_flags;
220 IpcDataEvMouseUp(unsigned long timestamp)
222 flags(EVAS_BUTTON_NONE),
224 timestamp(static_cast<unsigned int>(timestamp)),
225 event_flags(EVAS_EVENT_FLAG_NONE)
230 struct IpcDataEvMouseDown
233 Evas_Button_Flags flags;
235 unsigned int timestamp;
236 Evas_Event_Flags event_flags;
238 IpcDataEvMouseDown(unsigned long timestamp)
240 flags(EVAS_BUTTON_NONE),
242 timestamp(static_cast<unsigned int>(timestamp)),
243 event_flags(EVAS_EVENT_FLAG_NONE)
248 struct IpcDataEvMouseMove
251 Evas_Button_Flags flags;
253 unsigned int timestamp;
254 Evas_Event_Flags event_flags;
256 IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
257 : x(static_cast<Evas_Coord>(touchPoint.local.x)),
258 y(static_cast<Evas_Coord>(touchPoint.local.y)),
259 flags(EVAS_BUTTON_NONE),
261 timestamp(static_cast<unsigned int>(timestamp)),
262 event_flags(EVAS_EVENT_FLAG_NONE)
267 struct IpcDataEvMouseOut
269 unsigned int timestamp;
271 Evas_Event_Flags event_flags;
273 IpcDataEvMouseOut(unsigned long timestamp)
274 : timestamp(static_cast<unsigned int>(timestamp)),
276 event_flags(EVAS_EVENT_FLAG_NONE)
281 } // anonymous namespace
290 #if defined(DEBUG_ENABLED)
291 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
295 // Impl to hide EFL implementation.
296 struct Indicator::Impl
298 // Construction & Destruction
303 Impl(Indicator* indicator)
304 : mIndicator(indicator),
305 mEcoreEventHandler(NULL)
307 // Register Client message events for quick panel state.
308 mEcoreEventHandler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, EcoreEventClientMessage, this);
316 ecore_event_handler_del(mEcoreEventHandler);
320 * Called when the client messages (i.e. quick panel state) are received.
322 static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
324 Ecore_X_Event_Client_Message* clientMessageEvent((Ecore_X_Event_Client_Message*)event);
325 Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
327 if (clientMessageEvent == NULL || indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
329 return ECORE_CALLBACK_PASS_ON;
332 #ifndef DALI_PROFILE_UBUNTU
333 if (clientMessageEvent->message_type == ECORE_X_ATOM_E_INDICATOR_FLICK_DONE)
335 // if indicator is not showing, INDICATOR_FLICK_DONE is given
336 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
337 !indicatorImpl->mIndicator->mIsShowing )
339 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
342 else if( clientMessageEvent->message_type == ECORE_X_ATOM_E_MOVE_QUICKPANEL_STATE )
344 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
345 indicatorImpl->mIndicator->mIsShowing )
347 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
352 return ECORE_CALLBACK_PASS_ON;
356 Indicator* mIndicator;
357 Ecore_Event_Handler* mEcoreEventHandler;
361 Indicator::LockFile::LockFile(const std::string filename)
362 : mFilename(filename),
365 mFileDescriptor = open(filename.c_str(), O_RDWR);
366 if( mFileDescriptor == -1 )
370 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
374 Indicator::LockFile::~LockFile()
376 // Closing file descriptor also unlocks file.
377 close( mFileDescriptor );
380 bool Indicator::LockFile::Lock()
382 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
385 if( mFileDescriptor > 0 )
387 if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
395 // file descriptor is no longer valid or not writable
398 DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
406 void Indicator::LockFile::Unlock()
408 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
409 if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
413 // file descriptor is no longer valid or not writable
416 DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
421 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
423 bool error = mErrorThrown;
424 mErrorThrown = false;
428 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
429 : mLockFile(lockFile),
434 mLocked = mLockFile->Lock();
438 Indicator::ScopedLock::~ScopedLock()
446 bool Indicator::ScopedLock::IsLocked()
451 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
453 mGestureDetected( false ),
455 mOpacityMode( Dali::Window::OPAQUE ),
456 mState( DISCONNECTED ),
458 mServerConnection( NULL ),
459 mObserver( observer ),
460 mOrientation( orientation ),
463 mVisible( Dali::Window::INVISIBLE ),
465 mIsAnimationPlaying( false ),
466 mCurrentSharedFile( 0 ),
467 mSharedBufferType( BUFFER_TYPE_SHM ),
469 mBackgroundVisible( false )
471 mIndicatorContentActor = Dali::Actor::New();
472 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
473 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
475 // Indicator image handles the touch event including "leave"
476 mIndicatorContentActor.SetLeaveRequired( true );
477 mIndicatorContentActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
478 mIndicatorContentActor.SetColor( Color::BLACK );
480 mIndicatorActor = Dali::Actor::New();
481 mIndicatorActor.Add( mIndicatorContentActor );
483 // Event handler to find out flick down gesture
484 mEventActor = Dali::Actor::New();
485 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
486 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
487 mIndicatorActor.Add( mEventActor );
489 // Attach pan gesture to find flick down during hiding.
490 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
491 // since it consumes the pan gesture in advance.
492 mPanDetector = Dali::PanGestureDetector::New();
493 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
494 mPanDetector.Attach( mEventActor );
498 // register indicator to accessibility adaptor
499 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
500 if(accessibilityAdaptor)
502 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
504 // hide the indicator by default
505 mIndicatorActor.SetVisible( false );
508 // create impl to handle ecore event
509 mImpl = new Impl(this);
513 Indicator::~Indicator()
525 mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
530 void Indicator::SetAdaptor(Adaptor* adaptor)
533 mIndicatorBuffer->SetAdaptor( adaptor );
536 Dali::Actor Indicator::GetActor()
538 return mIndicatorActor;
541 void Indicator::Open( Dali::Window::WindowOrientation orientation )
543 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
545 // Calls from Window should be set up to ensure we are in a
546 // disconnected state before opening a second time.
547 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
549 mOrientation = orientation;
553 // Change background visibility depending on orientation
554 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
556 if( mBackgroundRenderer )
558 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
559 mBackgroundVisible = false;
564 SetOpacityMode( mOpacityMode );
568 void Indicator::Close()
570 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
572 if( mState == CONNECTED )
575 if( mObserver != NULL )
577 mObserver->IndicatorClosed( this );
581 Dali::Texture emptyTexture;
582 SetForegroundImage( emptyTexture );
585 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
589 Dali::Geometry geometry = CreateBackgroundGeometry();
592 if( mBackgroundRenderer )
594 if( mBackgroundRenderer.GetGeometry() != geometry )
596 mBackgroundRenderer.SetGeometry( geometry );
601 if( !mBackgroundShader )
603 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
606 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
609 if( !mBackgroundVisible )
611 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
612 mBackgroundVisible = true;
615 else if( mBackgroundRenderer )
617 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
618 mBackgroundVisible = false;
622 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
624 if ( visibleMode != mVisible || forceUpdate )
626 // If we were previously hidden, then we should update the image data before we display the indicator
627 if ( mVisible == Dali::Window::INVISIBLE )
629 UpdateImageData( mCurrentSharedFile );
632 if ( visibleMode == Dali::Window::INVISIBLE )
634 if (mServerConnection)
636 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
641 mIndicatorActor.SetVisible( true );
643 if( mServerConnection )
645 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
649 mVisible = visibleMode;
651 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
653 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
656 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
658 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
661 ShowIndicator( KEEP_SHOWING );
666 ShowIndicator( HIDE_NOW );
672 bool Indicator::IsConnected()
674 return ( mState == CONNECTED );
677 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
681 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
689 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
691 if( mServerConnection )
693 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
695 // Send touch event to indicator server when indicator is showing
696 if( CheckVisibleState() || mIsShowing )
698 switch( touchPoint.state )
700 case Dali::PointState::DOWN:
702 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
703 IpcDataEvMouseDown ipcDown( touchEvent.time );
704 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
705 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
707 if( mVisible == Dali::Window::AUTO )
709 // Stop hiding indicator
710 ShowIndicator( KEEP_SHOWING );
715 case Dali::PointState::MOTION:
717 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
718 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
722 case Dali::PointState::UP:
724 IpcDataEvMouseUp ipcUp( touchEvent.time );
725 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
727 if( mVisible == Dali::Window::AUTO )
730 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
735 case Dali::TouchPoint::Leave:
737 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
738 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
739 IpcDataEvMouseUp ipcOut( touchEvent.time );
740 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
755 bool Indicator::Connect()
757 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
759 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
761 bool connected = false;
763 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
764 if( mServerConnection )
766 connected = mServerConnection->IsConnected();
769 delete mServerConnection;
770 mServerConnection = NULL;
776 StartReconnectionTimer();
786 void Indicator::StartReconnectionTimer()
788 if( ! mReconnectTimer )
790 mReconnectTimer = Dali::Timer::New(1000);
791 mConnection.DisconnectAll();
792 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
794 mReconnectTimer.Start();
797 bool Indicator::OnReconnectTimer()
801 if( mState == DISCONNECTED )
812 void Indicator::Disconnect()
814 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
816 mState = DISCONNECTED;
818 delete mServerConnection;
819 mServerConnection = NULL;
821 ClearSharedFileInfo();
824 void Indicator::Resize( int width, int height )
835 if( mImageWidth != width || mImageHeight != height )
838 mImageHeight = height;
840 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
841 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
842 mEventActor.SetSize(mImageWidth, mImageHeight);
846 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
848 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
850 // epcEvent->ref == w
851 // epcEvent->ref_to == h
852 // epcEvent->response == buffer num
853 // epcEvent->data = lockfile + nul byte
855 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
856 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
858 int n = epcEvent->response;
860 if( n >= 0 && n < SHARED_FILE_NUMBER )
862 mCurrentSharedFile = n;
864 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
865 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
867 mSharedFileInfo[n].mLockFileName.clear();
869 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
871 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
872 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
877 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
879 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
881 // epcEvent->ref == shm id
882 // epcEvent->ref_to == shm num
883 // epcEvent->response == buffer num
884 // epcEvent->data = shm ref string + nul byte
886 if ( (epcEvent->data) &&
887 (epcEvent->size > 0) &&
888 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
890 int n = epcEvent->response;
892 if( n >= 0 && n < SHARED_FILE_NUMBER )
894 mCurrentSharedFile = n;
896 mSharedFileInfo[n].mSharedFileName.clear();
898 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
900 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
901 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
903 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
904 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
909 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
911 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
913 // epcEvent->ref == alpha
914 // epcEvent->ref_to == sys
915 // epcEvent->response == buffer num
917 if ( mSharedBufferType != BUFFER_TYPE_SHM )
922 int n = epcEvent->response;
924 if( n >= 0 && n < SHARED_FILE_NUMBER )
926 mCurrentSharedFile = n;
928 delete mSharedFileInfo[n].mSharedFile;
929 mSharedFileInfo[n].mSharedFile = NULL;
931 delete mSharedFileInfo[n].mLock;
932 mSharedFileInfo[n].mLock = NULL;
934 std::stringstream sharedFileID;
935 std::stringstream sharedFileNumber;
937 sharedFileID << mSharedFileInfo[n].mSharedFileID;
938 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
940 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
942 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
944 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
945 if( mSharedFileInfo[n].mSharedFile != NULL )
947 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
948 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
950 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
955 if( CheckVisibleState() )
957 // set default indicator type (enable the quick panel)
958 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
962 // set default indicator type (disable the quick panel)
963 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
966 SetVisible(mVisible);
971 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
973 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
975 // epcEvent->ref == pixmap id
976 // epcEvent->ref_to == type
977 // epcEvent->response == buffer num
979 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
981 mSharedBufferType = (BufferType)(epcEvent->ref_to);
983 ClearSharedFileInfo();
985 mPixmap = static_cast<PixmapId>(epcEvent->ref);
986 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
988 CreateNewPixmapImage();
990 if( CheckVisibleState() )
992 // set default indicator type (enable the quick panel)
993 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
997 // set default indicator type (disable the quick panel)
998 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1001 SetVisible(mVisible);
1005 void Indicator::UpdateImageData( int bufferNumber )
1007 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1009 if( mState == CONNECTED && mVisible )
1013 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1014 CopyToBuffer( bufferNumber );
1020 mAdaptor->RequestUpdateOnce();
1026 bool Indicator::CopyToBuffer( int bufferNumber )
1028 bool success = false;
1030 if( mSharedFileInfo[bufferNumber].mLock )
1032 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1033 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1037 else if( scopedLock.IsLocked() )
1039 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1040 size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1042 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1044 mAdaptor->RequestUpdateOnce();
1053 void Indicator::CreateNewPixmapImage()
1055 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
1056 Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
1058 if( nativeImageSource )
1060 Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
1061 SetForegroundImage( texture );
1062 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1063 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1064 mEventActor.SetSize( mImageWidth, mImageHeight );
1068 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1070 if( mObserver != NULL )
1072 mObserver->IndicatorClosed( this );
1074 // Don't do connection in this callback - strange things happen!
1075 StartReconnectionTimer();
1079 void Indicator::CreateNewImage( int bufferNumber )
1081 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1082 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1083 bool success = false;
1085 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1087 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1090 SetForegroundImage( texture );
1097 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1099 if( mObserver != NULL )
1101 mObserver->IndicatorClosed( this );
1103 // Don't do connection in this callback - strange things happen!
1104 StartReconnectionTimer();
1108 Dali::Geometry Indicator::CreateBackgroundGeometry()
1110 switch( mOpacityMode )
1112 case Dali::Window::TRANSLUCENT:
1113 if( !mTranslucentGeometry )
1115 // Construct 5 interval mesh
1129 struct BackgroundVertex
1135 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1136 BackgroundVertex vertices[ numVertices ];
1139 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1140 BackgroundVertex* currentVertex = vertices;
1141 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1143 currentVertex->mPosition = Vector2( -0.5f, d );
1144 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1147 currentVertex->mPosition = Vector2( 0.5f, d );
1148 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1153 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1154 unsigned short indices[ numIndices ];
1156 unsigned short* currentIndex = indices;
1157 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1159 *currentIndex++ = (2 * y);
1160 *currentIndex++ = (2 * y) + 3;
1161 *currentIndex++ = (2 * y) + 1;
1163 *currentIndex++ = (2 * y);
1164 *currentIndex++ = (2 * y) + 2;
1165 *currentIndex++ = (2 * y) + 3;
1168 Dali::Property::Map vertexFormat;
1169 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1170 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1171 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1172 vertexPropertyBuffer.SetData( vertices, numVertices );
1174 // Create the geometry object
1175 mTranslucentGeometry = Dali::Geometry::New();
1176 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1177 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1180 return mTranslucentGeometry;
1181 case Dali::Window::OPAQUE:
1183 if( !mSolidGeometry )
1186 struct BackgroundVertex
1192 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1193 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1196 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1198 Dali::Property::Map vertexFormat;
1199 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1200 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1201 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1202 vertexPropertyBuffer.SetData( vertices, 4 );
1205 // Create the geometry object
1206 mSolidGeometry = Dali::Geometry::New();
1207 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1208 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1211 return mSolidGeometry;
1212 case Dali::Window::TRANSPARENT:
1216 return Dali::Geometry();
1219 void Indicator::SetForegroundImage( Dali::Texture texture )
1221 if( !mForegroundRenderer && texture )
1224 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1226 // Create renderer from geometry and material
1227 Dali::Geometry quad = CreateQuadGeometry();
1228 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1229 // Make sure the foreground stays in front of the background
1230 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1232 // Set blend function
1233 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1234 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1235 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1236 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1238 // Create a texture-set and add to renderer
1240 Dali::TextureSet textureSet = Dali::TextureSet::New();
1241 textureSet.SetTexture( 0u, texture );
1242 mForegroundRenderer.SetTextures( textureSet );
1244 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1246 else if( mForegroundRenderer )
1248 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1249 textureSet.SetTexture( 0u, texture );
1252 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1254 Resize( texture.GetWidth(), texture.GetHeight() );
1258 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1260 if( mObserver != NULL )
1262 mObserver->IndicatorTypeChanged( indicatorType );
1266 void Indicator::DataReceived( void* event )
1268 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1269 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1271 switch( epcEvent->minor )
1275 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1278 //mAdaptor->RequestUpdateOnce();
1282 case OP_UPDATE_DONE:
1284 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1285 // epcEvent->response == display buffer #
1286 //UpdateImageData( epcEvent->response );
1291 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1292 SetSharedImageInfo( epcEvent );
1297 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1298 SetLockFileInfo( epcEvent );
1303 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1304 LoadSharedImage( epcEvent );
1309 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1310 LoadPixmapImage( epcEvent );
1315 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1317 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1319 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1320 Resize( newSize->w, newSize->h );
1326 int msgDomain = epcEvent->ref;
1327 int msgId = epcEvent->ref_to;
1329 void *msgData = NULL;
1330 int msgDataSize = 0;
1331 msgData = epcEvent->data;
1332 msgDataSize = epcEvent->size;
1334 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1336 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1340 case MSG_ID_INDICATOR_TYPE:
1342 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1343 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1344 OnIndicatorTypeChanged( *indicatorType );
1348 case MSG_ID_INDICATOR_START_ANIMATION:
1350 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1352 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1354 DALI_LOG_ERROR("Message data is incorrect\n");
1358 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1360 if(!CheckVisibleState())
1362 ShowIndicator( animData->duration /* n sec */ );
1374 void Indicator::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 Indicator::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 Indicator::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 Indicator::ShowIndicator(float duration)
1426 if( !mIndicatorAnimation )
1428 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1429 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::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, &Indicator::OnShowTimer);
1473 mShowTimer.SetInterval(1000* duration);
1476 if( mVisible == Dali::Window::AUTO )
1478 // check the stage touch
1479 Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1484 if(mShowTimer && mShowTimer.IsRunning())
1489 if( mVisible == Dali::Window::AUTO )
1491 // check the stage touch
1492 Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1497 bool Indicator::OnShowTimer()
1499 // after time up, hide indicator
1500 ShowIndicator( HIDE_NOW );
1505 void Indicator::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 Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1519 if( mServerConnection )
1521 switch( gesture.state )
1523 case Gesture::Started:
1525 mGestureDetected = false;
1527 // The gesture position is the current position after it has moved by the displacement.
1528 // We want to reference the original position.
1529 mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1532 // No break, Fall through
1533 case Gesture::Continuing:
1535 if( mVisible == Dali::Window::AUTO && !mIsShowing )
1537 // Only take one touch point
1538 if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1540 mGestureDeltaY += gesture.displacement.y;
1542 if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1544 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1545 mGestureDetected = true;
1553 case Gesture::Finished:
1554 case Gesture::Cancelled:
1556 // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1557 if( mVisible == Dali::Window::AUTO && mIsShowing )
1559 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1571 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1573 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1575 // when stage is touched while indicator is showing temporary, hide it
1576 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1578 switch( touchPoint.state )
1580 case Dali::PointState::DOWN:
1582 // if touch point is inside the indicator, indicator is not hidden
1583 if( mImageHeight < int(touchPoint.screen.y) )
1585 ShowIndicator( HIDE_NOW );