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 "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 <pixmap-image.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;
99 const float OPAQUE_THRESHOLD(0.99f);
100 const float TRANSPARENT_THRESHOLD(0.05f);
102 // indicator service name
103 const char* INDICATOR_SERVICE_NAME("elm_indicator");
105 // Copied from ecore_evas_extn_engine.h
119 OP_PROFILE_CHANGE_REQUEST,
120 OP_PROFILE_CHANGE_DONE,
137 // Copied from elm_conform.c
139 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
140 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
141 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
142 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
143 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
144 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
156 struct IpcIndicatorDataAnimation
162 struct IpcDataEvMouseUp
165 Evas_Button_Flags flags;
167 unsigned int timestamp;
168 Evas_Event_Flags event_flags;
170 IpcDataEvMouseUp(unsigned long timestamp)
172 flags(EVAS_BUTTON_NONE),
174 timestamp(static_cast<unsigned int>(timestamp)),
175 event_flags(EVAS_EVENT_FLAG_NONE)
180 struct IpcDataEvMouseDown
183 Evas_Button_Flags flags;
185 unsigned int timestamp;
186 Evas_Event_Flags event_flags;
188 IpcDataEvMouseDown(unsigned long timestamp)
190 flags(EVAS_BUTTON_NONE),
192 timestamp(static_cast<unsigned int>(timestamp)),
193 event_flags(EVAS_EVENT_FLAG_NONE)
198 struct IpcDataEvMouseMove
201 Evas_Button_Flags flags;
203 unsigned int timestamp;
204 Evas_Event_Flags event_flags;
206 IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
207 : x(static_cast<Evas_Coord>(touchPoint.local.x)),
208 y(static_cast<Evas_Coord>(touchPoint.local.y)),
209 flags(EVAS_BUTTON_NONE),
211 timestamp(static_cast<unsigned int>(timestamp)),
212 event_flags(EVAS_EVENT_FLAG_NONE)
217 struct IpcDataEvMouseOut
219 unsigned int timestamp;
221 Evas_Event_Flags event_flags;
223 IpcDataEvMouseOut(unsigned long timestamp)
224 : timestamp(static_cast<unsigned int>(timestamp)),
226 event_flags(EVAS_EVENT_FLAG_NONE)
231 } // anonymous namespace
240 #if defined(DEBUG_ENABLED)
241 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
245 Indicator::LockFile::LockFile(const std::string filename)
246 : mFilename(filename),
249 mFileDescriptor = open(filename.c_str(), O_RDWR);
250 if( mFileDescriptor == -1 )
254 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
258 Indicator::LockFile::~LockFile()
260 // Closing file descriptor also unlocks file.
261 close( mFileDescriptor );
264 bool Indicator::LockFile::Lock()
266 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
269 if( mFileDescriptor > 0 )
271 if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
279 // file descriptor is no longer valid or not writable
282 DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
290 void Indicator::LockFile::Unlock()
292 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
293 if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
297 // file descriptor is no longer valid or not writable
300 DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
305 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
307 bool error = mErrorThrown;
308 mErrorThrown = false;
312 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
313 : mLockFile(lockFile),
318 mLocked = mLockFile->Lock();
322 Indicator::ScopedLock::~ScopedLock()
330 bool Indicator::ScopedLock::IsLocked()
335 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, Observer* observer )
337 mGestureDetected( false ),
339 mOpacityMode( Dali::Window::OPAQUE ),
340 mState( DISCONNECTED ),
342 mServerConnection( NULL ),
343 mObserver( observer ),
344 mOrientation( orientation ),
347 mVisible( Dali::Window::INVISIBLE ),
349 mIsAnimationPlaying( false ),
350 mCurrentSharedFile( 0 )
352 mIndicatorImageActor = Dali::ImageActor::New();
353 mIndicatorImageActor.SetBlendFunc( Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE_MINUS_SRC_ALPHA,
354 Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE );
356 mIndicatorImageActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
357 mIndicatorImageActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
358 mIndicatorImageActor.SetSortModifier( 1.0f );
360 // Indicator image handles the touch event including "leave"
361 mIndicatorImageActor.SetLeaveRequired( true );
362 mIndicatorImageActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
364 mBackgroundActor = Dali::Actor::New();
365 mBackgroundActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
366 mBackgroundActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
367 mBackgroundActor.SetColor( Color::BLACK );
369 mIndicatorImageContainerActor = Dali::Actor::New();
370 mIndicatorImageContainerActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
371 mIndicatorImageContainerActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
372 mIndicatorImageContainerActor.Add( mBackgroundActor );
373 mIndicatorImageContainerActor.Add( mIndicatorImageActor );
375 mIndicatorActor = Dali::Actor::New();
376 mIndicatorActor.Add( mIndicatorImageContainerActor );
378 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
380 mBackgroundActor.SetVisible( false );
383 // Event handler to find out flick down gesture
384 mEventActor = Dali::Actor::New();
385 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
386 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
387 mIndicatorActor.Add( mEventActor );
389 // Attach pan gesture to find flick down during hiding.
390 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
391 // since it consumes the pan gesture in advance.
392 mPanDetector = Dali::PanGestureDetector::New();
393 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
394 mPanDetector.Attach( mEventActor );
398 // register indicator to accessibility adaptor
399 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
400 if(accessibilityAdaptor)
402 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
404 // hide the indicator by default
405 mIndicatorActor.SetVisible( false );
408 Indicator::~Indicator()
412 mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
417 void Indicator::SetAdaptor(Adaptor* adaptor)
420 mIndicatorBuffer->SetAdaptor( adaptor );
423 Dali::Actor Indicator::GetActor()
425 return mIndicatorActor;
428 void Indicator::Open( Dali::Window::WindowOrientation orientation )
430 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
432 // Calls from Window should be set up to ensure we are in a
433 // disconnected state before opening a second time.
434 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
436 mOrientation = orientation;
440 // Change background visibility depending on orientation
441 if(mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
443 mBackgroundActor.SetVisible( false );
447 SetOpacityMode( mOpacityMode );
451 void Indicator::Close()
453 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
455 if( mState == CONNECTED )
458 if( mObserver != NULL )
460 mObserver->IndicatorClosed( this );
464 Dali::Image emptyImage;
465 mIndicatorImageActor.SetImage(emptyImage);
468 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
472 //@todo replace with a gradient renderer when that is implemented
473 Dali::Geometry geometry = CreateBackgroundGeometry();
476 mBackgroundActor.SetVisible( true );
478 if( mBackgroundActor.GetRendererCount() > 0 )
480 Dali::Renderer renderer = mBackgroundActor.GetRendererAt( 0 );
483 if( renderer.GetGeometry() == geometry )
489 renderer.SetGeometry( geometry );
495 if( !mBackgroundMaterial )
497 Dali::Shader shader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT );
498 mBackgroundMaterial = Dali::Material::New( shader );
501 Dali::Renderer renderer = Dali::Renderer::New( geometry, mBackgroundMaterial );
503 mBackgroundActor.AddRenderer( renderer );
508 mBackgroundActor.SetVisible( false );
512 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
514 if ( visibleMode != mVisible || forceUpdate )
516 // If we were previously hidden, then we should update the image data before we display the indicator
517 if ( mVisible == Dali::Window::INVISIBLE )
519 UpdateImageData( mCurrentSharedFile );
521 if ( visibleMode != Dali::Window::INVISIBLE )
523 mIndicatorActor.SetVisible( true );
526 mVisible = visibleMode;
528 if( mIndicatorImageActor.GetImage() )
530 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
533 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
535 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
538 ShowIndicator( KEEP_SHOWING );
543 ShowIndicator( HIDE_NOW );
549 bool Indicator::IsConnected()
551 return ( mState == CONNECTED );
554 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
558 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
566 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
568 if( mServerConnection )
570 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
572 // Send touch event to indicator server when indicator is showing
573 if( CheckVisibleState() || mIsShowing )
575 switch( touchPoint.state )
577 case Dali::TouchPoint::Down:
579 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
580 IpcDataEvMouseDown ipcDown( touchEvent.time );
581 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
582 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
584 if( mVisible == Dali::Window::AUTO )
586 // Stop hiding indicator
587 ShowIndicator( KEEP_SHOWING );
592 case Dali::TouchPoint::Motion:
594 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
595 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
599 case Dali::TouchPoint::Up:
601 IpcDataEvMouseUp ipcUp( touchEvent.time );
602 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
604 if( mVisible == Dali::Window::AUTO )
607 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
612 case Dali::TouchPoint::Leave:
614 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
615 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
616 IpcDataEvMouseUp ipcOut( touchEvent.time );
617 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
632 bool Indicator::Connect()
634 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
636 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
638 bool connected = false;
640 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
641 if( mServerConnection )
643 connected = mServerConnection->IsConnected();
646 delete mServerConnection;
647 mServerConnection = NULL;
653 StartReconnectionTimer();
663 void Indicator::StartReconnectionTimer()
665 if( ! mReconnectTimer )
667 mReconnectTimer = Dali::Timer::New(1000);
668 mConnection.DisconnectAll();
669 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
671 mReconnectTimer.Start();
674 bool Indicator::OnReconnectTimer()
678 if( mState == DISCONNECTED )
689 void Indicator::Disconnect()
691 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
693 mState = DISCONNECTED;
695 delete mServerConnection;
696 mServerConnection = NULL;
698 ClearSharedFileInfo();
701 void Indicator::Resize( int width, int height )
712 if( mImageWidth != width || mImageHeight != height )
715 mImageHeight = height;
717 mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
718 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
719 mEventActor.SetSize(mImageWidth, mImageHeight);
720 mBackgroundActor.SetSize( mImageWidth, mImageHeight );
721 mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
725 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
727 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
729 // epcEvent->ref == w
730 // epcEvent->ref_to == h
731 // epcEvent->response == buffer num
732 // epcEvent->data = lockfile + nul byte
734 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
735 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
737 int n = epcEvent->response;
739 if( n >= 0 && n < SHARED_FILE_NUMBER )
741 mCurrentSharedFile = n;
743 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
744 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
746 mSharedFileInfo[n].mLockFileName.clear();
748 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
750 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
751 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
756 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
758 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
760 // epcEvent->ref == shm id
761 // epcEvent->ref_to == shm num
762 // epcEvent->response == buffer num
763 // epcEvent->data = shm ref string + nul byte
765 if ( (epcEvent->data) &&
766 (epcEvent->size > 0) &&
767 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
769 int n = epcEvent->response;
771 if( n >= 0 && n < SHARED_FILE_NUMBER )
773 mCurrentSharedFile = n;
775 mSharedFileInfo[n].mSharedFileName.clear();
777 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
779 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
780 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
782 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
783 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
788 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
790 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
792 // epcEvent->ref == alpha
793 // epcEvent->ref_to == sys
794 // epcEvent->response == buffer num
796 int n = epcEvent->response;
798 if( n >= 0 && n < SHARED_FILE_NUMBER )
800 mCurrentSharedFile = n;
802 delete mSharedFileInfo[n].mSharedFile;
803 mSharedFileInfo[n].mSharedFile = NULL;
805 delete mSharedFileInfo[n].mLock;
806 mSharedFileInfo[n].mLock = NULL;
808 std::stringstream sharedFileID;
809 std::stringstream sharedFileNumber;
811 sharedFileID << mSharedFileInfo[n].mSharedFileID;
812 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
814 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
816 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
818 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
819 if( mSharedFileInfo[n].mSharedFile != NULL )
821 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
822 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
824 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
829 if( CheckVisibleState() )
831 // set default indicator type (enable the quick panel)
832 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
836 // set default indicator type (disable the quick panel)
837 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
840 SetVisible(mVisible, true);
845 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
847 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
849 // epcEvent->ref == w
850 // epcEvent->ref_to == h
851 // epcEvent->response == alpha
852 // epcEvent->data = pixmap id
854 if( ( epcEvent->data ) &&
855 (epcEvent->size >= (int)sizeof(PixmapId)) )
857 ClearSharedFileInfo();
859 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
861 mImageWidth = epcEvent->ref;
862 mImageHeight = epcEvent->ref_to;
864 mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
865 CreateNewPixmapImage();
867 if( CheckVisibleState() )
869 // set default indicator type (enable the quick panel)
870 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
874 // set default indicator type (disable the quick panel)
875 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
878 SetVisible(mVisible, true);
883 void Indicator::UpdateImageData( int bufferNumber )
885 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
887 if( mState == CONNECTED && mVisible )
891 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
892 CopyToBuffer( bufferNumber );
898 mAdaptor->RequestUpdateOnce();
904 bool Indicator::CopyToBuffer( int bufferNumber )
906 bool success = false;
908 if( mSharedFileInfo[bufferNumber].mLock )
910 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
911 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
915 else if( scopedLock.IsLocked() )
917 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
918 size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
920 if( mIndicatorBuffer->UpdatePixels( src, size ) )
922 mAdaptor->RequestUpdateOnce();
931 void Indicator::CreateNewPixmapImage()
933 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
934 Dali::PixmapImagePtr pixmapImage = Dali::PixmapImage::New( mPixmap );
938 mIndicatorImageActor.SetImage( Dali::NativeImage::New(*pixmapImage) );
939 mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
940 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
941 mEventActor.SetSize(mImageWidth, mImageHeight);
942 mBackgroundActor.SetSize( mImageWidth, mImageHeight );
943 mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
947 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
949 if( mObserver != NULL )
951 mObserver->IndicatorClosed( this );
953 // Don't do connection in this callback - strange things happen!
954 StartReconnectionTimer();
958 void Indicator::CreateNewImage( int bufferNumber )
960 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
961 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
962 Dali::Image image = Dali::NativeImage::New( mIndicatorBuffer->GetNativeImage() );
964 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
966 mIndicatorImageActor.SetImage( image );
970 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
972 if( mObserver != NULL )
974 mObserver->IndicatorClosed( this );
976 // Don't do connection in this callback - strange things happen!
977 StartReconnectionTimer();
981 //@todo replace with a gradient renderer when that is implemented
982 Dali::Geometry Indicator::CreateBackgroundGeometry()
984 switch( mOpacityMode )
986 case Dali::Window::TRANSLUCENT:
987 if( !mTranslucentGeometry )
989 // Construct 5 interval mesh
1003 struct BackgroundVertex
1009 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1010 BackgroundVertex vertices[ numVertices ];
1013 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1014 BackgroundVertex* currentVertex = vertices;
1015 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1017 currentVertex->mPosition = Vector2( -0.5f, d );
1018 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1021 currentVertex->mPosition = Vector2( 0.5f, d );
1022 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1027 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1028 unsigned int indices[ numIndices ];
1030 unsigned int* currentIndex = indices;
1031 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1033 *currentIndex++ = (2 * y);
1034 *currentIndex++ = (2 * y) + 3;
1035 *currentIndex++ = (2 * y) + 1;
1037 *currentIndex++ = (2 * y);
1038 *currentIndex++ = (2 * y) + 2;
1039 *currentIndex++ = (2 * y) + 3;
1042 Dali::Property::Map vertexFormat;
1043 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1044 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1045 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat, numVertices );
1046 vertexPropertyBuffer.SetData( vertices );
1048 Dali::Property::Map indexFormat;
1049 indexFormat[ "indices" ] = Dali::Property::INTEGER;
1050 Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat, numIndices );
1051 indexPropertyBuffer.SetData( indices );
1053 // Create the geometry object
1054 mTranslucentGeometry = Dali::Geometry::New();
1055 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1056 mTranslucentGeometry.SetIndexBuffer( indexPropertyBuffer );
1059 return mTranslucentGeometry;
1060 case Dali::Window::OPAQUE:
1062 if( !mSolidGeometry )
1065 struct BackgroundVertex
1071 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1072 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1075 unsigned int indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1077 Dali::Property::Map vertexFormat;
1078 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1079 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1080 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat, 4 );
1081 vertexPropertyBuffer.SetData( vertices );
1083 Dali::Property::Map indexFormat;
1084 indexFormat[ "indices" ] = Dali::Property::INTEGER;
1085 Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat, 6 );
1086 indexPropertyBuffer.SetData( indices );
1088 // Create the geometry object
1089 mSolidGeometry = Dali::Geometry::New();
1090 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1091 mSolidGeometry.SetIndexBuffer( indexPropertyBuffer );
1094 return mSolidGeometry;
1095 case Dali::Window::TRANSPARENT:
1099 return Dali::Geometry();
1102 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1104 if( mObserver != NULL )
1106 mObserver->IndicatorTypeChanged( indicatorType );
1110 void Indicator::DataReceived( void* event )
1112 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1113 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1115 switch( epcEvent->minor )
1119 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1122 mAdaptor->RequestUpdateOnce();
1126 case OP_UPDATE_DONE:
1128 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1129 // epcEvent->response == display buffer #
1130 UpdateImageData( epcEvent->response );
1135 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1136 SetSharedImageInfo( epcEvent );
1141 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1142 SetLockFileInfo( epcEvent );
1147 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1148 LoadSharedImage( epcEvent );
1153 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1155 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1157 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1158 Resize( newSize->w, newSize->h );
1164 int msgDomain = epcEvent->ref;
1165 int msgId = epcEvent->ref_to;
1167 void *msgData = NULL;
1168 int msgDataSize = 0;
1169 msgData = epcEvent->data;
1170 msgDataSize = epcEvent->size;
1172 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1174 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1178 case MSG_ID_INDICATOR_TYPE:
1180 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1181 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1182 OnIndicatorTypeChanged( *indicatorType );
1186 case MSG_ID_INDICATOR_START_ANIMATION:
1188 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1190 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1192 DALI_LOG_ERROR("Message data is incorrect");
1196 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1198 if(!CheckVisibleState())
1200 ShowIndicator( animData->duration /* n sec */ );
1212 void Indicator::ConnectionClosed()
1214 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1216 // Will get this callback if the server connection failed to start up.
1217 delete mServerConnection;
1218 mServerConnection = NULL;
1219 mState = DISCONNECTED;
1221 // Attempt to re-connect
1225 bool Indicator::CheckVisibleState()
1227 if( mOrientation == Dali::Window::LANDSCAPE
1228 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1229 || (mVisible != Dali::Window::VISIBLE) )
1237 void Indicator::ClearSharedFileInfo()
1239 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1241 delete mSharedFileInfo[i].mLock;
1242 mSharedFileInfo[i].mLock = NULL;
1244 delete mSharedFileInfo[i].mSharedFile;
1245 mSharedFileInfo[i].mSharedFile = NULL;
1247 mSharedFileInfo[i].mLockFileName.clear();
1248 mSharedFileInfo[i].mSharedFileName.clear();
1253 * duration can be this
1257 * KEEP_SHOWING = -1,
1261 void Indicator::ShowIndicator(float duration)
1263 if( !mIndicatorAnimation )
1265 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1266 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1269 if(mIsShowing && !EqualsZero(duration))
1271 // If need to show during showing, do nothing.
1272 // In 2nd phase (below) will update timer
1274 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1276 // If need to hide during hiding or hidden already, do nothing
1280 if( EqualsZero(duration) )
1282 mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1286 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1290 mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1294 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1297 mIndicatorAnimation.Play();
1298 mIsAnimationPlaying = true;
1305 mShowTimer = Dali::Timer::New(1000 * duration);
1306 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1308 mShowTimer.SetInterval(1000* duration);
1311 if( mVisible == Dali::Window::AUTO )
1313 // check the stage touch
1314 Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1319 if(mShowTimer && mShowTimer.IsRunning())
1324 if( mVisible == Dali::Window::AUTO )
1326 // check the stage touch
1327 Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1332 bool Indicator::OnShowTimer()
1334 // after time up, hide indicator
1335 ShowIndicator( HIDE_NOW );
1340 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1342 mIsAnimationPlaying = false;
1343 // once animation is finished and indicator is hidden, take it off stage
1346 if( mObserver != NULL )
1348 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1353 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1355 if( mServerConnection )
1357 switch( gesture.state )
1359 case Gesture::Started:
1361 mGestureDetected = false;
1363 // The gesture position is the current position after it has moved by the displacement.
1364 // We want to reference the original position.
1365 mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1368 // No break, Fall through
1369 case Gesture::Continuing:
1371 if( mVisible == Dali::Window::AUTO && !mIsShowing )
1373 // Only take one touch point
1374 if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1376 mGestureDeltaY += gesture.displacement.y;
1378 if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1380 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1381 mGestureDetected = true;
1389 case Gesture::Finished:
1390 case Gesture::Cancelled:
1392 // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1393 if( mVisible == Dali::Window::AUTO && mIsShowing )
1395 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1407 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1409 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1411 // when stage is touched while indicator is showing temporary, hide it
1412 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1414 switch( touchPoint.state )
1416 case Dali::TouchPoint::Down:
1418 ShowIndicator( HIDE_NOW );