2 * Copyright (c) 2017 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"
22 // Ecore is littered with C style cast
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wold-style-cast"
28 #include <Ecore_Wayland.h>
33 #include <sys/types.h>
41 #include <dali/public-api/images/native-image.h>
42 #include <dali/public-api/events/touch-event.h>
43 #include <dali/public-api/events/touch-point.h>
44 #include <dali/public-api/common/stage.h>
45 #include <dali/public-api/images/buffer-image.h>
46 #include <dali/public-api/images/pixel.h>
48 #include <dali/integration-api/debug.h>
51 #include <adaptor-impl.h>
52 #include <accessibility-adaptor-impl.h>
53 #include <native-image-source.h>
57 #if defined(DEBUG_ENABLED)
58 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
64 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
65 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
66 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
74 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
75 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
77 #define MAKE_SHADER(A)#A
79 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
80 attribute mediump vec2 aPosition;
81 attribute mediump float aAlpha;
82 varying mediump float vAlpha;
83 uniform mediump mat4 uMvpMatrix;
84 uniform mediump vec3 uSize;
88 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
89 vertexPosition = uMvpMatrix * vertexPosition;
92 gl_Position = vertexPosition;
96 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
97 uniform lowp vec4 uColor;
98 varying mediump float vAlpha;
102 gl_FragColor = uColor;
103 gl_FragColor.a *= vAlpha;
107 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
108 attribute mediump vec2 aPosition;\n
109 varying mediump vec2 vTexCoord;\n
110 uniform mediump mat4 uMvpMatrix;\n
111 uniform mediump vec3 uSize;\n
112 uniform mediump vec4 sTextureRect;\n
116 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
117 vTexCoord = aPosition + vec2(0.5);\n
121 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
122 varying mediump vec2 vTexCoord;\n
123 uniform sampler2D sTexture;\n
127 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
131 Dali::Geometry CreateQuadGeometry()
133 Dali::Property::Map quadVertexFormat;
134 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
135 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
137 const float halfQuadSize = .5f;
138 struct QuadVertex { Dali::Vector2 position; };
139 QuadVertex quadVertexData[4] = {
140 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
141 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
142 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
143 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
144 vertexData.SetData(quadVertexData, 4);
146 Dali::Geometry quad = Dali::Geometry::New();
147 quad.AddVertexBuffer( vertexData );
148 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
152 const float OPAQUE_THRESHOLD(0.99f);
153 const float TRANSPARENT_THRESHOLD(0.05f);
155 // indicator service name
156 const char* INDICATOR_SERVICE_NAME("elm_indicator");
158 // Copied from ecore_evas_extn_engine.h
174 OP_PROFILE_CHANGE_REQUEST,
175 OP_PROFILE_CHANGE_DONE,
193 // Copied from elm_conform.c
195 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
196 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
197 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
198 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
199 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
200 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
212 struct IpcIndicatorDataAnimation
218 struct IpcDataEvMouseUp
221 Evas_Button_Flags flags;
223 unsigned int timestamp;
224 Evas_Event_Flags event_flags;
226 IpcDataEvMouseUp(unsigned long timestamp)
228 flags(EVAS_BUTTON_NONE),
230 timestamp(static_cast<unsigned int>(timestamp)),
231 event_flags(EVAS_EVENT_FLAG_NONE)
236 struct IpcDataEvMouseDown
239 Evas_Button_Flags flags;
241 unsigned int timestamp;
242 Evas_Event_Flags event_flags;
244 IpcDataEvMouseDown(unsigned long timestamp)
246 flags(EVAS_BUTTON_NONE),
248 timestamp(static_cast<unsigned int>(timestamp)),
249 event_flags(EVAS_EVENT_FLAG_NONE)
254 struct IpcDataEvMouseMove
257 Evas_Button_Flags flags;
259 unsigned int timestamp;
260 Evas_Event_Flags event_flags;
262 IpcDataEvMouseMove(const Dali::Vector2& touchPoint, unsigned long timestamp)
263 : x(static_cast<Evas_Coord>(touchPoint.x)),
264 y(static_cast<Evas_Coord>(touchPoint.y)),
265 flags(EVAS_BUTTON_NONE),
267 timestamp(static_cast<unsigned int>(timestamp)),
268 event_flags(EVAS_EVENT_FLAG_NONE)
273 struct IpcDataEvMouseOut
275 unsigned int timestamp;
277 Evas_Event_Flags event_flags;
279 IpcDataEvMouseOut(unsigned long timestamp)
280 : timestamp(static_cast<unsigned int>(timestamp)),
282 event_flags(EVAS_EVENT_FLAG_NONE)
287 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
289 void SaveIndicatorImage( Dali::NativeImageSourcePtr nativeImageSource )
291 // Save image data to disk in BMP form.
292 static int gFilenameCounter = 0;
293 static const char bmpHeader[] = {
294 0x42, 0x4d, 0x0a, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x7c, 0x00,
296 0xe0, 0x01, 0x00, 0x00, // Width (480)
297 0x1b, 0x00, 0x00, 0x00, // Height ( 27)
298 0x01, 0x00, 0x20, 0x00, 0x03, 0x00,
299 0x00, 0x00, 0x80, 0xca, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
301 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
308 // This is a BMP header with width & height hard-coded in.
309 // The data was first determined by dumping the raw data and inspecting in GIMP, before creating this header data.
310 std::vector<unsigned char> buffer;
313 Dali::Pixel::Format pixelFormat;
314 if( nativeImageSource->GetPixels( buffer, w, h, pixelFormat ) )
316 int imageSize = w * h * 4;
317 std::stringstream fileName;
318 // Give each file an incremental filename.
319 fileName << "/opt/usr/media/Images/out-" << std::setfill( '0' ) << std::setw( 5 ) << gFilenameCounter << ".bmp";
321 std::ofstream outfile( fileName.str().c_str(), std::ofstream::binary );
322 if( outfile.is_open() )
324 DALI_LOG_WARNING( "Saving Indicator Image w:%d, h:%d, %s\n", w, h, fileName.str().c_str() );
326 outfile.write( bmpHeader, sizeof( bmpHeader ) / sizeof( bmpHeader[0] ) ); // Size of the BMP header.
327 outfile.write( (const char*)buffer.data(), imageSize );
333 DALI_LOG_ERROR( "COULD NOT OPEN FOR SAVING: %s\n", fileName.str().c_str() );
340 } // anonymous namespace
349 #if defined(DEBUG_ENABLED)
350 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
353 // Impl to hide EFL implementation.
355 struct Indicator::Impl
357 enum // operation mode
360 INDICATOR_STAY_WITH_DURATION
366 Impl(Indicator* indicator)
367 : mIndicator(indicator),
368 mEcoreEventHandler(NULL)
370 #if defined(DALI_PROFILE_MOBILE)
372 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
374 mEcoreEventHandler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, EcoreEventClientMessage, this);
376 #endif // WAYLAND && DALI_PROFILE_MOBILE
384 if ( mEcoreEventHandler )
386 ecore_event_handler_del(mEcoreEventHandler);
390 static void SetIndicatorVisibility( void* data, int operation )
392 Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
394 if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
398 if ( operation == INDICATOR_STAY_WITH_DURATION )
400 // if indicator is not showing, INDICATOR_FLICK_DONE is given
401 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
402 !indicatorImpl->mIndicator->mIsShowing )
404 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
407 else if( operation == INDICATOR_HIDE )
409 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
410 indicatorImpl->mIndicator->mIsShowing )
412 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
416 #if defined(DALI_PROFILE_MOBILE)
419 * Called when the Ecore indicator event is received.
421 static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
423 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
424 return ECORE_CALLBACK_PASS_ON;
428 * Called when the client messages (i.e. quick panel state) are received.
430 static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
432 Ecore_X_Event_Client_Message* clientMessageEvent((Ecore_X_Event_Client_Message*)event);
434 if ( clientMessageEvent != NULL )
436 if (clientMessageEvent->message_type == ECORE_X_ATOM_E_INDICATOR_FLICK_DONE)
438 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
440 else if ( clientMessageEvent->message_type == ECORE_X_ATOM_E_MOVE_QUICKPANEL_STATE )
442 SetIndicatorVisibility( data, INDICATOR_HIDE );
445 return ECORE_CALLBACK_PASS_ON;
448 #endif // WAYLAND && DALI_PROFILE_MOBILE
451 Indicator* mIndicator;
452 Ecore_Event_Handler* mEcoreEventHandler;
455 Indicator::LockFile::LockFile(const std::string filename)
456 : mFilename(filename),
459 mFileDescriptor = open(filename.c_str(), O_RDWR);
460 if( mFileDescriptor == -1 )
464 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
468 Indicator::LockFile::~LockFile()
470 // Closing file descriptor also unlocks file.
471 if( mFileDescriptor > 0 )
473 close( mFileDescriptor );
477 bool Indicator::LockFile::Lock()
479 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
482 if( mFileDescriptor > 0 )
484 struct flock filelock;
486 filelock.l_type = F_RDLCK;
487 filelock.l_whence = SEEK_SET;
488 filelock.l_start = 0;
490 if( fcntl( mFileDescriptor, F_SETLKW, &filelock ) == -1 )
493 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
503 DALI_LOG_ERROR( "### Invalid fd ###\n" );
509 void Indicator::LockFile::Unlock()
511 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
513 if( mFileDescriptor > 0 )
515 struct flock filelock;
517 filelock.l_type = F_UNLCK;
518 filelock.l_whence = SEEK_SET;
519 filelock.l_start = 0;
521 if (fcntl(mFileDescriptor, F_SETLKW, &filelock) == -1)
524 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
529 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
531 bool error = mErrorThrown;
532 mErrorThrown = false;
536 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
537 : mLockFile(lockFile),
542 mLocked = mLockFile->Lock();
546 Indicator::ScopedLock::~ScopedLock()
554 bool Indicator::ScopedLock::IsLocked()
559 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
561 mGestureDeltaY( 0.0f ),
562 mGestureDetected( false ),
564 mOpacityMode( Dali::Window::OPAQUE ),
565 mState( DISCONNECTED ),
567 mServerConnection( NULL ),
568 mObserver( observer ),
569 mOrientation( orientation ),
572 mVisible( Dali::Window::INVISIBLE ),
574 mIsAnimationPlaying( false ),
575 mCurrentSharedFile( 0 ),
576 mSharedBufferType( BUFFER_TYPE_SHM ),
578 mBackgroundVisible( false ),
581 mIndicatorContentActor = Dali::Actor::New();
582 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
583 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
585 // Indicator image handles the touch event including "leave"
586 mIndicatorContentActor.SetLeaveRequired( true );
587 mIndicatorContentActor.TouchSignal().Connect( this, &Indicator::OnTouch );
588 mIndicatorContentActor.SetColor( Color::BLACK );
590 mIndicatorActor = Dali::Actor::New();
591 mIndicatorActor.Add( mIndicatorContentActor );
593 // Event handler to find out flick down gesture
594 mEventActor = Dali::Actor::New();
595 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
596 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
597 mIndicatorActor.Add( mEventActor );
599 // Attach pan gesture to find flick down during hiding.
600 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
601 // since it consumes the pan gesture in advance.
602 mPanDetector = Dali::PanGestureDetector::New();
603 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
604 mPanDetector.Attach( mEventActor );
608 // register indicator to accessibility adaptor
609 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
610 if(accessibilityAdaptor)
612 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
614 // hide the indicator by default
615 mIndicatorActor.SetVisible( false );
617 // create impl to handle ecore event
618 mImpl = new Impl(this);
621 Indicator::~Indicator()
631 mEventActor.TouchSignal().Disconnect( this, &Indicator::OnTouch );
636 void Indicator::SetAdaptor(Adaptor* adaptor)
639 mIndicatorBuffer->SetAdaptor( adaptor );
642 Dali::Actor Indicator::GetActor()
644 return mIndicatorActor;
647 void Indicator::Open( Dali::Window::WindowOrientation orientation )
649 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
651 // Calls from Window should be set up to ensure we are in a
652 // disconnected state before opening a second time.
653 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
655 mOrientation = orientation;
659 // Change background visibility depending on orientation
660 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
662 if( mBackgroundRenderer )
664 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
665 mBackgroundVisible = false;
670 SetOpacityMode( mOpacityMode );
674 void Indicator::Close()
676 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
678 if( mState == CONNECTED )
681 if( mObserver != NULL )
683 mObserver->IndicatorClosed( this );
687 Dali::Texture emptyTexture;
688 SetForegroundImage( emptyTexture );
691 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
695 Dali::Geometry geometry = CreateBackgroundGeometry();
698 if( mBackgroundRenderer )
700 if( mBackgroundRenderer.GetGeometry() != geometry )
702 mBackgroundRenderer.SetGeometry( geometry );
707 if( !mBackgroundShader )
709 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
712 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
715 if( !mBackgroundVisible )
717 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
718 mBackgroundVisible = true;
721 else if( mBackgroundRenderer )
723 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
724 mBackgroundVisible = false;
729 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
731 if ( visibleMode != mVisible || forceUpdate )
733 // If we were previously hidden, then we should update the image data before we display the indicator
734 if ( mVisible == Dali::Window::INVISIBLE )
736 UpdateImageData( mCurrentSharedFile );
739 if ( visibleMode == Dali::Window::INVISIBLE )
741 if (mServerConnection)
743 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
748 mIndicatorActor.SetVisible( true );
750 if( mServerConnection )
752 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
756 mVisible = visibleMode;
759 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
761 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
764 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
766 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
769 ShowIndicator( KEEP_SHOWING );
774 ShowIndicator( HIDE_NOW );
784 bool Indicator::IsConnected()
786 return ( mState == CONNECTED );
789 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
793 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
801 bool Indicator::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
803 if( mServerConnection )
805 // Send touch event to indicator server when indicator is showing
806 if( CheckVisibleState() || mIsShowing )
808 switch( touchData.GetState(0) )
810 case Dali::PointState::DOWN:
812 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
813 IpcDataEvMouseDown ipcDown( touchData.GetTime() );
814 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
815 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
817 if( mVisible == Dali::Window::AUTO )
819 // Stop hiding indicator
820 ShowIndicator( KEEP_SHOWING );
825 case Dali::PointState::MOTION:
827 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
828 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
832 case Dali::PointState::UP:
833 case Dali::PointState::INTERRUPTED:
835 IpcDataEvMouseUp ipcUp( touchData.GetTime() );
836 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
838 if( mVisible == Dali::Window::AUTO )
841 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
846 case Dali::TouchPoint::Leave:
848 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
849 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
850 IpcDataEvMouseUp ipcOut( touchData.GetTime() );
851 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
866 bool Indicator::Connect()
868 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
870 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
872 bool connected = false;
874 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
875 if( mServerConnection )
877 connected = mServerConnection->IsConnected();
880 delete mServerConnection;
881 mServerConnection = NULL;
887 StartReconnectionTimer();
897 void Indicator::StartReconnectionTimer()
899 if( ! mReconnectTimer )
901 mReconnectTimer = Dali::Timer::New(1000);
902 mConnection.DisconnectAll();
903 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
905 mReconnectTimer.Start();
908 bool Indicator::OnReconnectTimer()
912 if( mState == DISCONNECTED )
923 void Indicator::Disconnect()
925 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
927 mState = DISCONNECTED;
929 delete mServerConnection;
930 mServerConnection = NULL;
932 ClearSharedFileInfo();
935 void Indicator::Resize( int width, int height )
946 if( mImageWidth != width || mImageHeight != height )
949 mImageHeight = height;
951 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
952 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
953 mEventActor.SetSize(mImageWidth, mImageHeight);
958 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
960 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
962 // epcEvent->ref == w
963 // epcEvent->ref_to == h
964 // epcEvent->response == buffer num
965 // epcEvent->data = lockfile + nul byte
967 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
968 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
970 int n = epcEvent->response;
972 if( n >= 0 && n < SHARED_FILE_NUMBER )
974 mCurrentSharedFile = n;
976 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
977 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
979 mSharedFileInfo[n].mLockFileName.clear();
981 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
983 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
984 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
989 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
991 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
993 // epcEvent->ref == shm id
994 // epcEvent->ref_to == shm num
995 // epcEvent->response == buffer num
996 // epcEvent->data = shm ref string + nul byte
998 if ( (epcEvent->data) &&
999 (epcEvent->size > 0) &&
1000 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
1002 int n = epcEvent->response;
1004 if( n >= 0 && n < SHARED_FILE_NUMBER )
1006 mCurrentSharedFile = n;
1008 mSharedFileInfo[n].mSharedFileName.clear();
1010 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
1012 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
1013 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
1015 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
1016 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
1021 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1023 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1025 // epcEvent->ref == alpha
1026 // epcEvent->ref_to == sys
1027 // epcEvent->response == buffer num
1029 if ( mSharedBufferType != BUFFER_TYPE_SHM )
1034 int n = epcEvent->response;
1036 if( n >= 0 && n < SHARED_FILE_NUMBER )
1038 mCurrentSharedFile = n;
1040 delete mSharedFileInfo[n].mSharedFile;
1041 mSharedFileInfo[n].mSharedFile = NULL;
1043 delete mSharedFileInfo[n].mLock;
1044 mSharedFileInfo[n].mLock = NULL;
1046 std::stringstream sharedFileID;
1047 std::stringstream sharedFileNumber;
1049 sharedFileID << mSharedFileInfo[n].mSharedFileID;
1050 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
1052 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1054 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1056 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1057 if( mSharedFileInfo[n].mSharedFile != NULL )
1059 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
1060 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1062 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1066 CreateNewImage( n );
1073 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1075 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1077 // epcEvent->ref == pixmap id
1078 // epcEvent->ref_to == type
1079 // epcEvent->response == buffer num
1081 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
1083 mSharedBufferType = (BufferType)(epcEvent->ref_to);
1085 ClearSharedFileInfo();
1087 mPixmap = static_cast<PixmapId>(epcEvent->ref);
1088 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
1090 CreateNewPixmapImage();
1095 void Indicator::UpdateTopMargin()
1097 int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1098 if (mTopMargin != newMargin)
1100 mTopMargin = newMargin;
1101 mAdaptor->IndicatorSizeChanged( mTopMargin );
1105 void Indicator::UpdateVisibility()
1107 if( CheckVisibleState() )
1109 // set default indicator type (enable the quick panel)
1110 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1114 // set default indicator type (disable the quick panel)
1115 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1120 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1123 SetVisible(mVisible, true);
1126 void Indicator::UpdateImageData( int bufferNumber )
1128 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1130 if( mState == CONNECTED && mVisible )
1134 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1135 CopyToBuffer( bufferNumber );
1141 mAdaptor->RequestUpdateOnce();
1147 bool Indicator::CopyToBuffer( int bufferNumber )
1149 bool success = false;
1151 if( mSharedFileInfo[bufferNumber].mLock )
1153 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1154 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1158 else if( scopedLock.IsLocked() )
1160 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1161 size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1163 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1165 mAdaptor->RequestUpdateOnce();
1174 void Indicator::CreateNewPixmapImage()
1176 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
1177 Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
1179 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
1180 SaveIndicatorImage( nativeImageSource );
1183 if( nativeImageSource )
1185 Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
1186 SetForegroundImage( texture );
1187 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1188 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1189 mEventActor.SetSize( mImageWidth, mImageHeight );
1194 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1196 if( mObserver != NULL )
1198 mObserver->IndicatorClosed( this );
1200 // Don't do connection in this callback - strange things happen!
1201 StartReconnectionTimer();
1205 void Indicator::CreateNewImage( int bufferNumber )
1207 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1208 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1209 bool success = false;
1211 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1213 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1216 SetForegroundImage( texture );
1223 DALI_LOG_WARNING("### Cannot create indicator image ###\n");
1227 Dali::Geometry Indicator::CreateBackgroundGeometry()
1229 switch( mOpacityMode )
1231 case Dali::Window::TRANSLUCENT:
1232 if( !mTranslucentGeometry )
1234 // Construct 5 interval mesh
1248 struct BackgroundVertex
1254 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1255 BackgroundVertex vertices[ numVertices ];
1258 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1259 BackgroundVertex* currentVertex = vertices;
1260 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1262 currentVertex->mPosition = Vector2( -0.5f, d );
1263 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1266 currentVertex->mPosition = Vector2( 0.5f, d );
1267 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1272 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1273 unsigned short indices[ numIndices ];
1275 unsigned short* currentIndex = indices;
1276 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1278 *currentIndex++ = (2 * y);
1279 *currentIndex++ = (2 * y) + 3;
1280 *currentIndex++ = (2 * y) + 1;
1282 *currentIndex++ = (2 * y);
1283 *currentIndex++ = (2 * y) + 2;
1284 *currentIndex++ = (2 * y) + 3;
1287 Dali::Property::Map vertexFormat;
1288 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1289 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1290 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1291 vertexPropertyBuffer.SetData( vertices, numVertices );
1293 // Create the geometry object
1294 mTranslucentGeometry = Dali::Geometry::New();
1295 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1296 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1299 return mTranslucentGeometry;
1300 case Dali::Window::OPAQUE:
1302 if( !mSolidGeometry )
1305 struct BackgroundVertex
1311 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1312 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1315 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1317 Dali::Property::Map vertexFormat;
1318 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1319 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1320 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1321 vertexPropertyBuffer.SetData( vertices, 4 );
1324 // Create the geometry object
1325 mSolidGeometry = Dali::Geometry::New();
1326 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1327 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1330 return mSolidGeometry;
1331 case Dali::Window::TRANSPARENT:
1335 return Dali::Geometry();
1338 void Indicator::SetForegroundImage( Dali::Texture texture )
1340 if( !mForegroundRenderer && texture )
1343 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1345 // Create renderer from geometry and material
1346 Dali::Geometry quad = CreateQuadGeometry();
1347 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1348 // Make sure the foreground stays in front of the background
1349 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1351 // Set blend function
1352 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1353 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1354 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1355 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1357 // Create a texture-set and add to renderer
1359 Dali::TextureSet textureSet = Dali::TextureSet::New();
1360 textureSet.SetTexture( 0u, texture );
1361 mForegroundRenderer.SetTextures( textureSet );
1363 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1365 else if( mForegroundRenderer )
1367 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1368 textureSet.SetTexture( 0u, texture );
1371 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1373 Resize( texture.GetWidth(), texture.GetHeight() );
1377 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1379 if( mObserver != NULL )
1381 mObserver->IndicatorTypeChanged( indicatorType );
1385 void Indicator::DataReceived( void* event )
1387 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1388 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1390 switch( epcEvent->minor )
1394 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1397 mAdaptor->RequestUpdateOnce();
1401 case OP_UPDATE_DONE:
1403 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1404 // epcEvent->response == display buffer #
1405 UpdateImageData( epcEvent->response );
1410 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1411 SetSharedImageInfo( epcEvent );
1416 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1417 SetLockFileInfo( epcEvent );
1422 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1423 LoadSharedImage( epcEvent );
1428 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1429 LoadPixmapImage( epcEvent );
1434 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1436 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1438 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1439 Resize( newSize->w, newSize->h );
1445 int msgDomain = epcEvent->ref;
1446 int msgId = epcEvent->ref_to;
1448 void *msgData = NULL;
1449 int msgDataSize = 0;
1450 msgData = epcEvent->data;
1451 msgDataSize = epcEvent->size;
1453 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1455 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1459 case MSG_ID_INDICATOR_TYPE:
1461 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1462 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1463 OnIndicatorTypeChanged( *indicatorType );
1467 case MSG_ID_INDICATOR_START_ANIMATION:
1469 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1471 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1473 DALI_LOG_ERROR("Message data is incorrect\n");
1477 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1479 if(!CheckVisibleState())
1481 ShowIndicator( animData->duration /* n sec */ );
1492 void Indicator::ConnectionClosed()
1494 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1496 // Will get this callback if the server connection failed to start up.
1497 delete mServerConnection;
1498 mServerConnection = NULL;
1499 mState = DISCONNECTED;
1501 // Attempt to re-connect
1505 bool Indicator::CheckVisibleState()
1507 if( mOrientation == Dali::Window::LANDSCAPE
1508 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1509 || (mVisible == Dali::Window::INVISIBLE)
1510 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1518 void Indicator::ClearSharedFileInfo()
1520 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1522 delete mSharedFileInfo[i].mLock;
1523 mSharedFileInfo[i].mLock = NULL;
1525 delete mSharedFileInfo[i].mSharedFile;
1526 mSharedFileInfo[i].mSharedFile = NULL;
1528 mSharedFileInfo[i].mLockFileName.clear();
1529 mSharedFileInfo[i].mSharedFileName.clear();
1534 * duration can be this
1538 * KEEP_SHOWING = -1,
1542 void Indicator::ShowIndicator(float duration)
1544 if( !mIndicatorAnimation )
1546 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1547 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1550 if(mIsShowing && !EqualsZero(duration))
1552 // If need to show during showing, do nothing.
1553 // In 2nd phase (below) will update timer
1555 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1557 // If need to hide during hiding or hidden already, do nothing
1561 mIndicatorAnimation.Clear();
1563 if( EqualsZero(duration) )
1565 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1569 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1573 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1577 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1580 mIndicatorAnimation.Play();
1581 mIsAnimationPlaying = true;
1588 mShowTimer = Dali::Timer::New(1000 * duration);
1589 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1591 mShowTimer.SetInterval(1000* duration);
1594 if( mVisible == Dali::Window::AUTO )
1596 // check the stage touch
1597 Dali::Stage::GetCurrent().TouchSignal().Connect( this, &Indicator::OnStageTouch );
1602 if(mShowTimer && mShowTimer.IsRunning())
1607 if( mVisible == Dali::Window::AUTO )
1609 // check the stage touch
1610 Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &Indicator::OnStageTouch );
1615 bool Indicator::OnShowTimer()
1617 // after time up, hide indicator
1618 ShowIndicator( HIDE_NOW );
1623 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1625 mIsAnimationPlaying = false;
1626 // once animation is finished and indicator is hidden, take it off stage
1627 if( mObserver != NULL )
1629 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1633 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1635 // Nothing to do, but we still want to consume pan
1638 void Indicator::OnStageTouch(const Dali::TouchData& touchData)
1640 // when stage is touched while indicator is showing temporary, hide it
1641 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1643 switch( touchData.GetState(0) )
1645 case Dali::PointState::DOWN:
1647 // if touch point is inside the indicator, indicator is not hidden
1648 if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
1650 ShowIndicator( HIDE_NOW );
1667 #pragma GCC diagnostic pop