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 <Ecore_Wayland.h>
30 #include <sys/types.h>
36 #include <dali/public-api/images/native-image.h>
37 #include <dali/public-api/events/touch-event.h>
38 #include <dali/public-api/events/touch-point.h>
39 #include <dali/public-api/common/stage.h>
40 #include <dali/public-api/actors/blending.h>
41 #include <dali/public-api/shader-effects/shader-effect.h>
42 #include <dali/public-api/images/buffer-image.h>
44 #include <dali/integration-api/debug.h>
47 #include <adaptor-impl.h>
48 #include <accessibility-adaptor-impl.h>
49 #include <native-image-source.h>
53 #if defined(DEBUG_ENABLED)
54 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
60 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
61 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
62 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
70 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
71 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
73 #define MAKE_SHADER(A)#A
75 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
76 attribute mediump vec2 aPosition;
77 attribute mediump float aAlpha;
78 varying mediump float vAlpha;
79 uniform mediump mat4 uMvpMatrix;
80 uniform mediump vec3 uSize;
84 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
85 vertexPosition = uMvpMatrix * vertexPosition;
88 gl_Position = vertexPosition;
92 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
93 uniform lowp vec4 uColor;
94 varying mediump float vAlpha;
98 gl_FragColor = uColor;
99 gl_FragColor.a *= vAlpha;
103 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
104 attribute mediump vec2 aPosition;\n
105 varying mediump vec2 vTexCoord;\n
106 uniform mediump mat4 uMvpMatrix;\n
107 uniform mediump vec3 uSize;\n
108 uniform mediump vec4 sTextureRect;\n
112 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
113 vTexCoord = aPosition + vec2(0.5);\n
117 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
118 varying mediump vec2 vTexCoord;\n
119 uniform sampler2D sTexture;\n
123 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
127 Dali::Geometry CreateQuadGeometry()
129 Dali::Property::Map quadVertexFormat;
130 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
131 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
133 const float halfQuadSize = .5f;
134 struct QuadVertex { Dali::Vector2 position; };
135 QuadVertex quadVertexData[4] = {
136 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
137 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
138 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
139 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
140 vertexData.SetData(quadVertexData, 4);
142 Dali::Geometry quad = Dali::Geometry::New();
143 quad.AddVertexBuffer( vertexData );
144 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
148 const float OPAQUE_THRESHOLD(0.99f);
149 const float TRANSPARENT_THRESHOLD(0.05f);
151 // indicator service name
152 const char* INDICATOR_SERVICE_NAME("elm_indicator");
154 // Copied from ecore_evas_extn_engine.h
170 OP_PROFILE_CHANGE_REQUEST,
171 OP_PROFILE_CHANGE_DONE,
189 // Copied from elm_conform.c
191 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
192 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
193 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
194 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
195 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
196 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
208 struct IpcIndicatorDataAnimation
214 struct IpcDataEvMouseUp
217 Evas_Button_Flags flags;
219 unsigned int timestamp;
220 Evas_Event_Flags event_flags;
222 IpcDataEvMouseUp(unsigned long timestamp)
224 flags(EVAS_BUTTON_NONE),
226 timestamp(static_cast<unsigned int>(timestamp)),
227 event_flags(EVAS_EVENT_FLAG_NONE)
232 struct IpcDataEvMouseDown
235 Evas_Button_Flags flags;
237 unsigned int timestamp;
238 Evas_Event_Flags event_flags;
240 IpcDataEvMouseDown(unsigned long timestamp)
242 flags(EVAS_BUTTON_NONE),
244 timestamp(static_cast<unsigned int>(timestamp)),
245 event_flags(EVAS_EVENT_FLAG_NONE)
250 struct IpcDataEvMouseMove
253 Evas_Button_Flags flags;
255 unsigned int timestamp;
256 Evas_Event_Flags event_flags;
258 IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
259 : x(static_cast<Evas_Coord>(touchPoint.local.x)),
260 y(static_cast<Evas_Coord>(touchPoint.local.y)),
261 flags(EVAS_BUTTON_NONE),
263 timestamp(static_cast<unsigned int>(timestamp)),
264 event_flags(EVAS_EVENT_FLAG_NONE)
269 struct IpcDataEvMouseOut
271 unsigned int timestamp;
273 Evas_Event_Flags event_flags;
275 IpcDataEvMouseOut(unsigned long timestamp)
276 : timestamp(static_cast<unsigned int>(timestamp)),
278 event_flags(EVAS_EVENT_FLAG_NONE)
283 } // anonymous namespace
292 #if defined(DEBUG_ENABLED)
293 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
296 // Impl to hide EFL implementation.
298 struct Indicator::Impl
300 enum // operation mode
303 INDICATOR_STAY_WITH_DURATION
309 Impl(Indicator* indicator)
310 : mIndicator(indicator),
311 mEcoreEventHandler(NULL)
313 #if defined(DALI_PROFILE_MOBILE)
315 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
317 mEcoreEventHandler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, EcoreEventClientMessage, this);
319 #endif // WAYLAND && DALI_PROFILE_MOBILE
327 if ( mEcoreEventHandler )
329 ecore_event_handler_del(mEcoreEventHandler);
333 static void SetIndicatorVisibility( void* data, int operation )
335 Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
337 if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
341 if ( operation == INDICATOR_STAY_WITH_DURATION )
343 // if indicator is not showing, INDICATOR_FLICK_DONE is given
344 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
345 !indicatorImpl->mIndicator->mIsShowing )
347 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
350 else if( operation == INDICATOR_HIDE )
352 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
353 indicatorImpl->mIndicator->mIsShowing )
355 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
359 #if defined(DALI_PROFILE_MOBILE)
362 * Called when the Ecore indicator event is received.
364 static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
366 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
367 return ECORE_CALLBACK_PASS_ON;
371 * Called when the client messages (i.e. quick panel state) are received.
373 static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
375 Ecore_X_Event_Client_Message* clientMessageEvent((Ecore_X_Event_Client_Message*)event);
377 if ( clientMessageEvent != NULL )
379 if (clientMessageEvent->message_type == ECORE_X_ATOM_E_INDICATOR_FLICK_DONE)
381 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
383 else if ( clientMessageEvent->message_type == ECORE_X_ATOM_E_MOVE_QUICKPANEL_STATE )
385 SetIndicatorVisibility( data, INDICATOR_HIDE );
388 return ECORE_CALLBACK_PASS_ON;
391 #endif // WAYLAND && DALI_PROFILE_MOBILE
394 Indicator* mIndicator;
395 Ecore_Event_Handler* mEcoreEventHandler;
398 Indicator::LockFile::LockFile(const std::string filename)
399 : mFilename(filename),
402 mFileDescriptor = open(filename.c_str(), O_RDWR);
403 if( mFileDescriptor == -1 )
407 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
411 Indicator::LockFile::~LockFile()
413 // Closing file descriptor also unlocks file.
414 close( mFileDescriptor );
417 bool Indicator::LockFile::Lock()
419 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
422 if( mFileDescriptor > 0 )
424 if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
432 // file descriptor is no longer valid or not writable
435 DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
443 void Indicator::LockFile::Unlock()
445 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
446 if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
450 // file descriptor is no longer valid or not writable
453 DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
458 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
460 bool error = mErrorThrown;
461 mErrorThrown = false;
465 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
466 : mLockFile(lockFile),
471 mLocked = mLockFile->Lock();
475 Indicator::ScopedLock::~ScopedLock()
483 bool Indicator::ScopedLock::IsLocked()
488 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
490 mGestureDetected( false ),
492 mOpacityMode( Dali::Window::OPAQUE ),
493 mState( DISCONNECTED ),
495 mServerConnection( NULL ),
496 mObserver( observer ),
497 mOrientation( orientation ),
500 mVisible( Dali::Window::INVISIBLE ),
502 mIsAnimationPlaying( false ),
503 mCurrentSharedFile( 0 ),
504 mSharedBufferType( BUFFER_TYPE_SHM ),
506 mBackgroundVisible( false )
508 mIndicatorContentActor = Dali::Actor::New();
509 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
510 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
512 // Indicator image handles the touch event including "leave"
513 mIndicatorContentActor.SetLeaveRequired( true );
514 mIndicatorContentActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
515 mIndicatorContentActor.SetColor( Color::BLACK );
517 mIndicatorActor = Dali::Actor::New();
518 mIndicatorActor.Add( mIndicatorContentActor );
520 // Event handler to find out flick down gesture
521 mEventActor = Dali::Actor::New();
522 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
523 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
524 mIndicatorActor.Add( mEventActor );
526 // Attach pan gesture to find flick down during hiding.
527 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
528 // since it consumes the pan gesture in advance.
529 mPanDetector = Dali::PanGestureDetector::New();
530 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
531 mPanDetector.Attach( mEventActor );
535 // register indicator to accessibility adaptor
536 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
537 if(accessibilityAdaptor)
539 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
541 // hide the indicator by default
542 mIndicatorActor.SetVisible( false );
544 // create impl to handle ecore event
545 mImpl = new Impl(this);
548 Indicator::~Indicator()
558 mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
563 void Indicator::SetAdaptor(Adaptor* adaptor)
566 mIndicatorBuffer->SetAdaptor( adaptor );
569 Dali::Actor Indicator::GetActor()
571 return mIndicatorActor;
574 void Indicator::Open( Dali::Window::WindowOrientation orientation )
576 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
578 // Calls from Window should be set up to ensure we are in a
579 // disconnected state before opening a second time.
580 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
582 mOrientation = orientation;
586 // Change background visibility depending on orientation
587 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
589 if( mBackgroundRenderer )
591 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
592 mBackgroundVisible = false;
597 SetOpacityMode( mOpacityMode );
601 void Indicator::Close()
603 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
605 if( mState == CONNECTED )
608 if( mObserver != NULL )
610 mObserver->IndicatorClosed( this );
614 Dali::Texture emptyTexture;
615 SetForegroundImage( emptyTexture );
618 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
622 Dali::Geometry geometry = CreateBackgroundGeometry();
625 if( mBackgroundRenderer )
627 if( mBackgroundRenderer.GetGeometry() != geometry )
629 mBackgroundRenderer.SetGeometry( geometry );
634 if( !mBackgroundShader )
636 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
639 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
642 if( !mBackgroundVisible )
644 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
645 mBackgroundVisible = true;
648 else if( mBackgroundRenderer )
650 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
651 mBackgroundVisible = false;
655 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
657 if ( visibleMode != mVisible || forceUpdate )
659 // If we were previously hidden, then we should update the image data before we display the indicator
660 if ( mVisible == Dali::Window::INVISIBLE )
662 UpdateImageData( mCurrentSharedFile );
665 if ( visibleMode == Dali::Window::INVISIBLE )
667 if (mServerConnection)
669 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
674 mIndicatorActor.SetVisible( true );
676 if( mServerConnection )
678 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
682 mVisible = visibleMode;
684 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
686 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
689 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
691 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
694 ShowIndicator( KEEP_SHOWING );
699 ShowIndicator( HIDE_NOW );
709 bool Indicator::IsConnected()
711 return ( mState == CONNECTED );
714 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
718 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
726 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
728 if( mServerConnection )
730 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
732 // Send touch event to indicator server when indicator is showing
733 if( CheckVisibleState() || mIsShowing )
735 switch( touchPoint.state )
737 case Dali::PointState::DOWN:
739 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
740 IpcDataEvMouseDown ipcDown( touchEvent.time );
741 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
742 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
744 if( mVisible == Dali::Window::AUTO )
746 // Stop hiding indicator
747 ShowIndicator( KEEP_SHOWING );
752 case Dali::PointState::MOTION:
754 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
755 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
759 case Dali::PointState::UP:
760 case Dali::PointState::INTERRUPTED:
762 IpcDataEvMouseUp ipcUp( touchEvent.time );
763 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
765 if( mVisible == Dali::Window::AUTO )
768 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
773 case Dali::TouchPoint::Leave:
775 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
776 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
777 IpcDataEvMouseUp ipcOut( touchEvent.time );
778 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
793 bool Indicator::Connect()
795 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
797 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
799 bool connected = false;
801 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
802 if( mServerConnection )
804 connected = mServerConnection->IsConnected();
807 delete mServerConnection;
808 mServerConnection = NULL;
814 StartReconnectionTimer();
824 void Indicator::StartReconnectionTimer()
826 if( ! mReconnectTimer )
828 mReconnectTimer = Dali::Timer::New(1000);
829 mConnection.DisconnectAll();
830 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
832 mReconnectTimer.Start();
835 bool Indicator::OnReconnectTimer()
839 if( mState == DISCONNECTED )
850 void Indicator::Disconnect()
852 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
854 mState = DISCONNECTED;
856 delete mServerConnection;
857 mServerConnection = NULL;
859 ClearSharedFileInfo();
862 void Indicator::Resize( int width, int height )
873 if( mImageWidth != width || mImageHeight != height )
876 mImageHeight = height;
878 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
879 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
880 mEventActor.SetSize(mImageWidth, mImageHeight);
884 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
886 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
888 // epcEvent->ref == w
889 // epcEvent->ref_to == h
890 // epcEvent->response == buffer num
891 // epcEvent->data = lockfile + nul byte
893 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
894 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
896 int n = epcEvent->response;
898 if( n >= 0 && n < SHARED_FILE_NUMBER )
900 mCurrentSharedFile = n;
902 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
903 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
905 mSharedFileInfo[n].mLockFileName.clear();
907 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
909 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
910 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
915 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
917 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
919 // epcEvent->ref == shm id
920 // epcEvent->ref_to == shm num
921 // epcEvent->response == buffer num
922 // epcEvent->data = shm ref string + nul byte
924 if ( (epcEvent->data) &&
925 (epcEvent->size > 0) &&
926 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
928 int n = epcEvent->response;
930 if( n >= 0 && n < SHARED_FILE_NUMBER )
932 mCurrentSharedFile = n;
934 mSharedFileInfo[n].mSharedFileName.clear();
936 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
938 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
939 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
941 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
942 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
947 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
949 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
951 // epcEvent->ref == alpha
952 // epcEvent->ref_to == sys
953 // epcEvent->response == buffer num
955 if ( mSharedBufferType != BUFFER_TYPE_SHM )
960 int n = epcEvent->response;
962 if( n >= 0 && n < SHARED_FILE_NUMBER )
964 mCurrentSharedFile = n;
966 delete mSharedFileInfo[n].mSharedFile;
967 mSharedFileInfo[n].mSharedFile = NULL;
969 delete mSharedFileInfo[n].mLock;
970 mSharedFileInfo[n].mLock = NULL;
972 std::stringstream sharedFileID;
973 std::stringstream sharedFileNumber;
975 sharedFileID << mSharedFileInfo[n].mSharedFileID;
976 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
978 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
980 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
982 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
983 if( mSharedFileInfo[n].mSharedFile != NULL )
985 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
986 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
988 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
997 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
999 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1001 // epcEvent->ref == pixmap id
1002 // epcEvent->ref_to == type
1003 // epcEvent->response == buffer num
1005 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
1007 mSharedBufferType = (BufferType)(epcEvent->ref_to);
1009 ClearSharedFileInfo();
1011 mPixmap = static_cast<PixmapId>(epcEvent->ref);
1012 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
1014 CreateNewPixmapImage();
1019 void Indicator::UpdateVisibility()
1021 if( CheckVisibleState() )
1023 // set default indicator type (enable the quick panel)
1024 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1028 // set default indicator type (disable the quick panel)
1029 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1034 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1037 SetVisible(mVisible, true);
1040 void Indicator::UpdateImageData( int bufferNumber )
1042 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1044 if( mState == CONNECTED && mVisible )
1048 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1049 CopyToBuffer( bufferNumber );
1055 mAdaptor->RequestUpdateOnce();
1061 bool Indicator::CopyToBuffer( int bufferNumber )
1063 bool success = false;
1065 if( mSharedFileInfo[bufferNumber].mLock )
1067 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1068 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1072 else if( scopedLock.IsLocked() )
1074 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1075 size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1077 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1079 mAdaptor->RequestUpdateOnce();
1088 void Indicator::CreateNewPixmapImage()
1090 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
1091 Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
1093 if( nativeImageSource )
1095 Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
1096 SetForegroundImage( texture );
1097 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1098 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1099 mEventActor.SetSize( mImageWidth, mImageHeight );
1103 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1105 if( mObserver != NULL )
1107 mObserver->IndicatorClosed( this );
1109 // Don't do connection in this callback - strange things happen!
1110 StartReconnectionTimer();
1114 void Indicator::CreateNewImage( int bufferNumber )
1116 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1117 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1118 bool success = false;
1120 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1122 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1125 SetForegroundImage( texture );
1132 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1134 if( mObserver != NULL )
1136 mObserver->IndicatorClosed( this );
1138 // Don't do connection in this callback - strange things happen!
1139 StartReconnectionTimer();
1143 Dali::Geometry Indicator::CreateBackgroundGeometry()
1145 switch( mOpacityMode )
1147 case Dali::Window::TRANSLUCENT:
1148 if( !mTranslucentGeometry )
1150 // Construct 5 interval mesh
1164 struct BackgroundVertex
1170 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1171 BackgroundVertex vertices[ numVertices ];
1174 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1175 BackgroundVertex* currentVertex = vertices;
1176 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1178 currentVertex->mPosition = Vector2( -0.5f, d );
1179 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1182 currentVertex->mPosition = Vector2( 0.5f, d );
1183 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1188 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1189 unsigned short indices[ numIndices ];
1191 unsigned short* currentIndex = indices;
1192 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1194 *currentIndex++ = (2 * y);
1195 *currentIndex++ = (2 * y) + 3;
1196 *currentIndex++ = (2 * y) + 1;
1198 *currentIndex++ = (2 * y);
1199 *currentIndex++ = (2 * y) + 2;
1200 *currentIndex++ = (2 * y) + 3;
1203 Dali::Property::Map vertexFormat;
1204 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1205 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1206 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1207 vertexPropertyBuffer.SetData( vertices, numVertices );
1209 // Create the geometry object
1210 mTranslucentGeometry = Dali::Geometry::New();
1211 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1212 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1215 return mTranslucentGeometry;
1216 case Dali::Window::OPAQUE:
1218 if( !mSolidGeometry )
1221 struct BackgroundVertex
1227 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1228 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1231 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1233 Dali::Property::Map vertexFormat;
1234 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1235 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1236 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1237 vertexPropertyBuffer.SetData( vertices, 4 );
1240 // Create the geometry object
1241 mSolidGeometry = Dali::Geometry::New();
1242 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1243 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1246 return mSolidGeometry;
1247 case Dali::Window::TRANSPARENT:
1251 return Dali::Geometry();
1254 void Indicator::SetForegroundImage( Dali::Texture texture )
1256 if( !mForegroundRenderer && texture )
1259 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1261 // Create renderer from geometry and material
1262 Dali::Geometry quad = CreateQuadGeometry();
1263 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1264 // Make sure the foreground stays in front of the background
1265 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1267 // Set blend function
1268 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1269 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1270 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1271 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1273 // Create a texture-set and add to renderer
1275 Dali::TextureSet textureSet = Dali::TextureSet::New();
1276 textureSet.SetTexture( 0u, texture );
1277 mForegroundRenderer.SetTextures( textureSet );
1279 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1281 else if( mForegroundRenderer )
1283 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1284 textureSet.SetTexture( 0u, texture );
1287 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1289 Resize( texture.GetWidth(), texture.GetHeight() );
1293 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1295 if( mObserver != NULL )
1297 mObserver->IndicatorTypeChanged( indicatorType );
1301 void Indicator::DataReceived( void* event )
1303 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1304 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1306 switch( epcEvent->minor )
1310 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1313 //mAdaptor->RequestUpdateOnce();
1317 case OP_UPDATE_DONE:
1319 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1320 // epcEvent->response == display buffer #
1321 //UpdateImageData( epcEvent->response );
1326 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1327 SetSharedImageInfo( epcEvent );
1332 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1333 SetLockFileInfo( epcEvent );
1338 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1339 LoadSharedImage( epcEvent );
1344 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1345 LoadPixmapImage( epcEvent );
1350 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1352 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1354 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1355 Resize( newSize->w, newSize->h );
1361 int msgDomain = epcEvent->ref;
1362 int msgId = epcEvent->ref_to;
1364 void *msgData = NULL;
1365 int msgDataSize = 0;
1366 msgData = epcEvent->data;
1367 msgDataSize = epcEvent->size;
1369 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1371 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1375 case MSG_ID_INDICATOR_TYPE:
1377 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1378 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1379 OnIndicatorTypeChanged( *indicatorType );
1383 case MSG_ID_INDICATOR_START_ANIMATION:
1385 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1387 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1389 DALI_LOG_ERROR("Message data is incorrect\n");
1393 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1395 if(!CheckVisibleState())
1397 ShowIndicator( animData->duration /* n sec */ );
1408 void Indicator::ConnectionClosed()
1410 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1412 // Will get this callback if the server connection failed to start up.
1413 delete mServerConnection;
1414 mServerConnection = NULL;
1415 mState = DISCONNECTED;
1417 // Attempt to re-connect
1421 bool Indicator::CheckVisibleState()
1423 if( mOrientation == Dali::Window::LANDSCAPE
1424 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1425 || (mVisible == Dali::Window::INVISIBLE)
1426 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1434 void Indicator::ClearSharedFileInfo()
1436 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1438 delete mSharedFileInfo[i].mLock;
1439 mSharedFileInfo[i].mLock = NULL;
1441 delete mSharedFileInfo[i].mSharedFile;
1442 mSharedFileInfo[i].mSharedFile = NULL;
1444 mSharedFileInfo[i].mLockFileName.clear();
1445 mSharedFileInfo[i].mSharedFileName.clear();
1450 * duration can be this
1454 * KEEP_SHOWING = -1,
1458 void Indicator::ShowIndicator(float duration)
1460 if( !mIndicatorAnimation )
1462 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1463 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1466 if(mIsShowing && !EqualsZero(duration))
1468 // If need to show during showing, do nothing.
1469 // In 2nd phase (below) will update timer
1471 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1473 // If need to hide during hiding or hidden already, do nothing
1477 mIndicatorAnimation.Clear();
1479 if( EqualsZero(duration) )
1481 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1485 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1489 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1493 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1496 mIndicatorAnimation.Play();
1497 mIsAnimationPlaying = true;
1504 mShowTimer = Dali::Timer::New(1000 * duration);
1505 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1507 mShowTimer.SetInterval(1000* duration);
1510 if( mVisible == Dali::Window::AUTO )
1512 // check the stage touch
1513 Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1518 if(mShowTimer && mShowTimer.IsRunning())
1523 if( mVisible == Dali::Window::AUTO )
1525 // check the stage touch
1526 Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1531 bool Indicator::OnShowTimer()
1533 // after time up, hide indicator
1534 ShowIndicator( HIDE_NOW );
1539 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1541 mIsAnimationPlaying = false;
1542 // once animation is finished and indicator is hidden, take it off stage
1543 if( mObserver != NULL )
1545 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1549 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1553 if( mServerConnection )
1555 switch( gesture.state )
1557 case Gesture::Started:
1559 mGestureDetected = false;
1561 // The gesture position is the current position after it has moved by the displacement.
1562 // We want to reference the original position.
1563 mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1566 // No break, Fall through
1567 case Gesture::Continuing:
1569 if( mVisible == Dali::Window::AUTO && !mIsShowing )
1571 // Only take one touch point
1572 if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1574 mGestureDeltaY += gesture.displacement.y;
1576 if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1578 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1579 mGestureDetected = true;
1587 case Gesture::Finished:
1588 case Gesture::Cancelled:
1590 // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1591 if( mVisible == Dali::Window::AUTO && mIsShowing )
1593 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1605 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1607 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1609 // when stage is touched while indicator is showing temporary, hide it
1610 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1612 switch( touchPoint.state )
1614 case Dali::PointState::DOWN:
1616 // if touch point is inside the indicator, indicator is not hidden
1617 if( mImageHeight < int(touchPoint.screen.y) )
1619 ShowIndicator( HIDE_NOW );