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 <dali/internal/window-system/common/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"
27 #ifdef WAYLAND // WAYLAND
28 #ifdef ECORE_WL2 //ECORE_WL2
29 #include <Ecore_Wl2.h>
31 #include <Ecore_Wayland.h>
37 #include <sys/types.h>
45 #include <dali/public-api/images/native-image.h>
46 #include <dali/public-api/events/touch-event.h>
47 #include <dali/public-api/events/touch-point.h>
48 #include <dali/public-api/common/stage.h>
49 #include <dali/public-api/images/buffer-image.h>
50 #include <dali/public-api/images/pixel.h>
52 #include <dali/integration-api/debug.h>
55 #include <dali/internal/adaptor/common/adaptor-impl.h>
56 #include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
57 #include <dali/public-api/adaptor-framework/native-image-source.h>
61 #if defined(DEBUG_ENABLED)
62 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
68 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
69 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
70 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
78 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
79 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
81 #define MAKE_SHADER(A)#A
83 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
84 attribute mediump vec2 aPosition;
85 attribute mediump float aAlpha;
86 varying mediump float vAlpha;
87 uniform mediump mat4 uMvpMatrix;
88 uniform mediump vec3 uSize;
92 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
93 vertexPosition = uMvpMatrix * vertexPosition;
96 gl_Position = vertexPosition;
100 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
101 uniform lowp vec4 uColor;
102 varying mediump float vAlpha;
106 gl_FragColor = uColor;
107 gl_FragColor.a *= vAlpha;
111 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
112 attribute mediump vec2 aPosition;\n
113 varying mediump vec2 vTexCoord;\n
114 uniform mediump mat4 uMvpMatrix;\n
115 uniform mediump vec3 uSize;\n
116 uniform mediump vec4 sTextureRect;\n
120 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
121 vTexCoord = aPosition + vec2(0.5);\n
125 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
126 varying mediump vec2 vTexCoord;\n
127 uniform sampler2D sTexture;\n
131 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
135 Dali::Geometry CreateQuadGeometry()
137 Dali::Property::Map quadVertexFormat;
138 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
139 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
141 const float halfQuadSize = .5f;
142 struct QuadVertex { Dali::Vector2 position; };
143 QuadVertex quadVertexData[4] = {
144 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
145 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
146 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
147 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
148 vertexData.SetData(quadVertexData, 4);
150 Dali::Geometry quad = Dali::Geometry::New();
151 quad.AddVertexBuffer( vertexData );
152 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
156 const float OPAQUE_THRESHOLD(0.99f);
157 const float TRANSPARENT_THRESHOLD(0.05f);
159 // indicator service name
160 const char* INDICATOR_SERVICE_NAME("elm_indicator");
162 // Copied from ecore_evas_extn_engine.h
178 OP_PROFILE_CHANGE_REQUEST,
179 OP_PROFILE_CHANGE_DONE,
197 // Copied from elm_conform.c
199 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
200 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
201 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
202 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
203 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
204 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
216 struct IpcIndicatorDataAnimation
222 struct IpcDataEvMouseUp
225 Evas_Button_Flags flags;
227 unsigned int timestamp;
228 Evas_Event_Flags event_flags;
230 IpcDataEvMouseUp(unsigned long timestamp)
232 flags(EVAS_BUTTON_NONE),
234 timestamp(static_cast<unsigned int>(timestamp)),
235 event_flags(EVAS_EVENT_FLAG_NONE)
240 struct IpcDataEvMouseDown
243 Evas_Button_Flags flags;
245 unsigned int timestamp;
246 Evas_Event_Flags event_flags;
248 IpcDataEvMouseDown(unsigned long timestamp)
250 flags(EVAS_BUTTON_NONE),
252 timestamp(static_cast<unsigned int>(timestamp)),
253 event_flags(EVAS_EVENT_FLAG_NONE)
258 struct IpcDataEvMouseMove
261 Evas_Button_Flags flags;
263 unsigned int timestamp;
264 Evas_Event_Flags event_flags;
266 IpcDataEvMouseMove(const Dali::Vector2& touchPoint, unsigned long timestamp)
267 : x(static_cast<Evas_Coord>(touchPoint.x)),
268 y(static_cast<Evas_Coord>(touchPoint.y)),
269 flags(EVAS_BUTTON_NONE),
271 timestamp(static_cast<unsigned int>(timestamp)),
272 event_flags(EVAS_EVENT_FLAG_NONE)
277 struct IpcDataEvMouseOut
279 unsigned int timestamp;
281 Evas_Event_Flags event_flags;
283 IpcDataEvMouseOut(unsigned long timestamp)
284 : timestamp(static_cast<unsigned int>(timestamp)),
286 event_flags(EVAS_EVENT_FLAG_NONE)
291 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
293 void SaveIndicatorImage( Dali::NativeImageSourcePtr nativeImageSource )
295 // Save image data to disk in BMP form.
296 static int gFilenameCounter = 0;
297 static const char bmpHeader[] = {
298 0x42, 0x4d, 0x0a, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x7c, 0x00,
300 0xe0, 0x01, 0x00, 0x00, // Width (480)
301 0x1b, 0x00, 0x00, 0x00, // Height ( 27)
302 0x01, 0x00, 0x20, 0x00, 0x03, 0x00,
303 0x00, 0x00, 0x80, 0xca, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
305 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
312 // This is a BMP header with width & height hard-coded in.
313 // The data was first determined by dumping the raw data and inspecting in GIMP, before creating this header data.
314 std::vector<unsigned char> buffer;
317 Dali::Pixel::Format pixelFormat;
318 if( nativeImageSource->GetPixels( buffer, w, h, pixelFormat ) )
320 int imageSize = w * h * 4;
321 std::stringstream fileName;
322 // Give each file an incremental filename.
323 fileName << "/opt/usr/media/Images/out-" << std::setfill( '0' ) << std::setw( 5 ) << gFilenameCounter << ".bmp";
325 std::ofstream outfile( fileName.str().c_str(), std::ofstream::binary );
326 if( outfile.is_open() )
328 DALI_LOG_WARNING( "Saving Indicator Image w:%d, h:%d, %s\n", w, h, fileName.str().c_str() );
330 outfile.write( bmpHeader, sizeof( bmpHeader ) / sizeof( bmpHeader[0] ) ); // Size of the BMP header.
331 outfile.write( (const char*)buffer.data(), imageSize );
337 DALI_LOG_ERROR( "COULD NOT OPEN FOR SAVING: %s\n", fileName.str().c_str() );
344 } // anonymous namespace
353 #if defined(DEBUG_ENABLED)
354 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
357 // Impl to hide EFL implementation.
359 struct Indicator::Impl
361 enum // operation mode
364 INDICATOR_STAY_WITH_DURATION
370 Impl(Indicator* indicator)
371 : mIndicator(indicator),
372 mEcoreEventHandler(NULL)
374 #if defined(DALI_PROFILE_MOBILE)
376 #if defined(ECORE_WL2)
377 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL2_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
379 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
382 mEcoreEventHandler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, EcoreEventClientMessage, this);
384 #endif // WAYLAND && DALI_PROFILE_MOBILE
392 if ( mEcoreEventHandler )
394 ecore_event_handler_del(mEcoreEventHandler);
398 static void SetIndicatorVisibility( void* data, int operation )
400 Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
402 if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
406 if ( operation == INDICATOR_STAY_WITH_DURATION )
408 // if indicator is not showing, INDICATOR_FLICK_DONE is given
409 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
410 !indicatorImpl->mIndicator->mIsShowing )
412 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
415 else if( operation == INDICATOR_HIDE )
417 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
418 indicatorImpl->mIndicator->mIsShowing )
420 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
424 #if defined(DALI_PROFILE_MOBILE)
427 * Called when the Ecore indicator event is received.
429 static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
431 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
432 return ECORE_CALLBACK_PASS_ON;
436 * Called when the client messages (i.e. quick panel state) are received.
438 static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
440 Ecore_X_Event_Client_Message* clientMessageEvent((Ecore_X_Event_Client_Message*)event);
442 if ( clientMessageEvent != NULL )
444 if (clientMessageEvent->message_type == ECORE_X_ATOM_E_INDICATOR_FLICK_DONE)
446 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
448 else if ( clientMessageEvent->message_type == ECORE_X_ATOM_E_MOVE_QUICKPANEL_STATE )
450 SetIndicatorVisibility( data, INDICATOR_HIDE );
453 return ECORE_CALLBACK_PASS_ON;
456 #endif // WAYLAND && DALI_PROFILE_MOBILE
459 Indicator* mIndicator;
460 Ecore_Event_Handler* mEcoreEventHandler;
463 Indicator::LockFile::LockFile(const std::string filename)
464 : mFilename(filename),
467 mFileDescriptor = open(filename.c_str(), O_RDWR);
468 if( mFileDescriptor == -1 )
472 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
476 Indicator::LockFile::~LockFile()
478 // Closing file descriptor also unlocks file.
479 if( mFileDescriptor > 0 )
481 close( mFileDescriptor );
485 bool Indicator::LockFile::Lock()
487 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
490 if( mFileDescriptor > 0 )
492 struct flock filelock;
494 filelock.l_type = F_RDLCK;
495 filelock.l_whence = SEEK_SET;
496 filelock.l_start = 0;
498 if( fcntl( mFileDescriptor, F_SETLKW, &filelock ) == -1 )
501 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
511 DALI_LOG_ERROR( "### Invalid fd ###\n" );
517 void Indicator::LockFile::Unlock()
519 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
521 if( mFileDescriptor > 0 )
523 struct flock filelock;
525 filelock.l_type = F_UNLCK;
526 filelock.l_whence = SEEK_SET;
527 filelock.l_start = 0;
529 if (fcntl(mFileDescriptor, F_SETLKW, &filelock) == -1)
532 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
537 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
539 bool error = mErrorThrown;
540 mErrorThrown = false;
544 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
545 : mLockFile(lockFile),
550 mLocked = mLockFile->Lock();
554 Indicator::ScopedLock::~ScopedLock()
562 bool Indicator::ScopedLock::IsLocked()
567 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
569 mGestureDeltaY( 0.0f ),
570 mGestureDetected( false ),
572 mOpacityMode( Dali::Window::OPAQUE ),
573 mState( DISCONNECTED ),
575 mServerConnection( NULL ),
576 mObserver( observer ),
577 mOrientation( orientation ),
580 mVisible( Dali::Window::INVISIBLE ),
582 mIsAnimationPlaying( false ),
583 mCurrentSharedFile( 0 ),
584 mSharedBufferType( BUFFER_TYPE_SHM ),
586 mBackgroundVisible( false ),
589 mIndicatorContentActor = Dali::Actor::New();
590 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
591 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
593 // Indicator image handles the touch event including "leave"
594 mIndicatorContentActor.SetLeaveRequired( true );
595 mIndicatorContentActor.TouchSignal().Connect( this, &Indicator::OnTouch );
596 mIndicatorContentActor.SetColor( Color::BLACK );
598 mIndicatorActor = Dali::Actor::New();
599 mIndicatorActor.Add( mIndicatorContentActor );
601 // Event handler to find out flick down gesture
602 mEventActor = Dali::Actor::New();
603 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
604 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
605 mIndicatorActor.Add( mEventActor );
607 // Attach pan gesture to find flick down during hiding.
608 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
609 // since it consumes the pan gesture in advance.
610 mPanDetector = Dali::PanGestureDetector::New();
611 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
612 mPanDetector.Attach( mEventActor );
616 // register indicator to accessibility adaptor
617 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
618 if(accessibilityAdaptor)
620 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
622 // hide the indicator by default
623 mIndicatorActor.SetVisible( false );
625 // create impl to handle ecore event
626 mImpl = new Impl(this);
629 Indicator::~Indicator()
639 mEventActor.TouchSignal().Disconnect( this, &Indicator::OnTouch );
644 void Indicator::SetAdaptor(Adaptor* adaptor)
647 mIndicatorBuffer->SetAdaptor( adaptor );
650 Dali::Actor Indicator::GetActor()
652 return mIndicatorActor;
655 void Indicator::Open( Dali::Window::WindowOrientation orientation )
657 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
659 // Calls from Window should be set up to ensure we are in a
660 // disconnected state before opening a second time.
661 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
663 mOrientation = orientation;
667 // Change background visibility depending on orientation
668 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
670 if( mBackgroundRenderer )
672 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
673 mBackgroundVisible = false;
678 SetOpacityMode( mOpacityMode );
682 void Indicator::Close()
684 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
686 if( mState == CONNECTED )
689 if( mObserver != NULL )
691 mObserver->IndicatorClosed( this );
695 Dali::Texture emptyTexture;
696 SetForegroundImage( emptyTexture );
699 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
703 Dali::Geometry geometry = CreateBackgroundGeometry();
706 if( mBackgroundRenderer )
708 if( mBackgroundRenderer.GetGeometry() != geometry )
710 mBackgroundRenderer.SetGeometry( geometry );
715 if( !mBackgroundShader )
717 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
720 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
723 if( !mBackgroundVisible )
725 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
726 mBackgroundVisible = true;
729 else if( mBackgroundRenderer )
731 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
732 mBackgroundVisible = false;
737 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
739 if ( visibleMode != mVisible || forceUpdate )
741 // If we were previously hidden, then we should update the image data before we display the indicator
742 if ( mVisible == Dali::Window::INVISIBLE )
744 UpdateImageData( mCurrentSharedFile );
747 if ( visibleMode == Dali::Window::INVISIBLE )
749 if (mServerConnection)
751 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
756 mIndicatorActor.SetVisible( true );
758 if( mServerConnection )
760 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
764 mVisible = visibleMode;
767 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
769 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
772 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
774 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
777 ShowIndicator( KEEP_SHOWING );
782 ShowIndicator( HIDE_NOW );
792 bool Indicator::IsConnected()
794 return ( mState == CONNECTED );
797 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
801 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
809 bool Indicator::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
811 if( mServerConnection )
813 // Send touch event to indicator server when indicator is showing
814 if( CheckVisibleState() || mIsShowing )
816 switch( touchData.GetState(0) )
818 case Dali::PointState::DOWN:
820 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
821 IpcDataEvMouseDown ipcDown( touchData.GetTime() );
822 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
823 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
825 if( mVisible == Dali::Window::AUTO )
827 // Stop hiding indicator
828 ShowIndicator( KEEP_SHOWING );
833 case Dali::PointState::MOTION:
835 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
836 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
840 case Dali::PointState::UP:
841 case Dali::PointState::INTERRUPTED:
843 IpcDataEvMouseUp ipcUp( touchData.GetTime() );
844 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
846 if( mVisible == Dali::Window::AUTO )
849 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
854 case Dali::TouchPoint::Leave:
856 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
857 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
858 IpcDataEvMouseUp ipcOut( touchData.GetTime() );
859 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
874 bool Indicator::Connect()
876 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
878 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
880 bool connected = false;
882 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
883 if( mServerConnection )
885 connected = mServerConnection->IsConnected();
888 delete mServerConnection;
889 mServerConnection = NULL;
895 StartReconnectionTimer();
905 void Indicator::StartReconnectionTimer()
907 if( ! mReconnectTimer )
909 mReconnectTimer = Dali::Timer::New(1000);
910 mConnection.DisconnectAll();
911 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
913 mReconnectTimer.Start();
916 bool Indicator::OnReconnectTimer()
920 if( mState == DISCONNECTED )
931 void Indicator::Disconnect()
933 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
935 mState = DISCONNECTED;
937 delete mServerConnection;
938 mServerConnection = NULL;
940 ClearSharedFileInfo();
943 void Indicator::Resize( int width, int height )
954 if( mImageWidth != width || mImageHeight != height )
957 mImageHeight = height;
959 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
960 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
961 mEventActor.SetSize(mImageWidth, mImageHeight);
966 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
968 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
970 // epcEvent->ref == w
971 // epcEvent->ref_to == h
972 // epcEvent->response == buffer num
973 // epcEvent->data = lockfile + nul byte
975 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
976 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
978 int n = epcEvent->response;
980 if( n >= 0 && n < SHARED_FILE_NUMBER )
982 mCurrentSharedFile = n;
984 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
985 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
987 mSharedFileInfo[n].mLockFileName.clear();
989 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
991 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
992 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
997 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
999 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1001 // epcEvent->ref == shm id
1002 // epcEvent->ref_to == shm num
1003 // epcEvent->response == buffer num
1004 // epcEvent->data = shm ref string + nul byte
1006 if ( (epcEvent->data) &&
1007 (epcEvent->size > 0) &&
1008 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
1010 int n = epcEvent->response;
1012 if( n >= 0 && n < SHARED_FILE_NUMBER )
1014 mCurrentSharedFile = n;
1016 mSharedFileInfo[n].mSharedFileName.clear();
1018 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
1020 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
1021 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
1023 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
1024 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
1029 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1031 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1033 // epcEvent->ref == alpha
1034 // epcEvent->ref_to == sys
1035 // epcEvent->response == buffer num
1037 if ( mSharedBufferType != BUFFER_TYPE_SHM )
1042 int n = epcEvent->response;
1044 if( n >= 0 && n < SHARED_FILE_NUMBER )
1046 mCurrentSharedFile = n;
1048 delete mSharedFileInfo[n].mSharedFile;
1049 mSharedFileInfo[n].mSharedFile = NULL;
1051 delete mSharedFileInfo[n].mLock;
1052 mSharedFileInfo[n].mLock = NULL;
1054 std::stringstream sharedFileID;
1055 std::stringstream sharedFileNumber;
1057 sharedFileID << mSharedFileInfo[n].mSharedFileID;
1058 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
1060 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1062 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1064 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1065 if( mSharedFileInfo[n].mSharedFile != NULL )
1067 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
1068 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1070 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1074 CreateNewImage( n );
1081 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1083 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1085 // epcEvent->ref == pixmap id
1086 // epcEvent->ref_to == type
1087 // epcEvent->response == buffer num
1089 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
1091 mSharedBufferType = (BufferType)(epcEvent->ref_to);
1093 ClearSharedFileInfo();
1095 mPixmap = static_cast<PixmapId>(epcEvent->ref);
1096 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
1098 CreateNewPixmapImage();
1103 void Indicator::UpdateTopMargin()
1105 int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1106 if (mTopMargin != newMargin)
1108 mTopMargin = newMargin;
1109 mAdaptor->IndicatorSizeChanged( mTopMargin );
1113 void Indicator::UpdateVisibility()
1115 if( CheckVisibleState() )
1117 // set default indicator type (enable the quick panel)
1118 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1122 // set default indicator type (disable the quick panel)
1123 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1128 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1131 SetVisible(mVisible, true);
1134 void Indicator::UpdateImageData( int bufferNumber )
1136 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1138 if( mState == CONNECTED && mVisible )
1142 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1143 CopyToBuffer( bufferNumber );
1149 mAdaptor->RequestUpdateOnce();
1155 bool Indicator::CopyToBuffer( int bufferNumber )
1157 bool success = false;
1159 if( mSharedFileInfo[bufferNumber].mLock )
1161 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1162 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1166 else if( scopedLock.IsLocked() )
1168 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1169 size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1171 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1173 mAdaptor->RequestUpdateOnce();
1182 void Indicator::CreateNewPixmapImage()
1184 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
1185 Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
1187 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
1188 SaveIndicatorImage( nativeImageSource );
1191 if( nativeImageSource )
1193 Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
1194 SetForegroundImage( texture );
1195 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1196 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1197 mEventActor.SetSize( mImageWidth, mImageHeight );
1202 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1204 if( mObserver != NULL )
1206 mObserver->IndicatorClosed( this );
1208 // Don't do connection in this callback - strange things happen!
1209 StartReconnectionTimer();
1213 void Indicator::CreateNewImage( int bufferNumber )
1215 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1216 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1217 bool success = false;
1219 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1221 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1224 SetForegroundImage( texture );
1231 DALI_LOG_WARNING("### Cannot create indicator image ###\n");
1235 Dali::Geometry Indicator::CreateBackgroundGeometry()
1237 switch( mOpacityMode )
1239 case Dali::Window::TRANSLUCENT:
1240 if( !mTranslucentGeometry )
1242 // Construct 5 interval mesh
1256 struct BackgroundVertex
1262 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1263 BackgroundVertex vertices[ numVertices ];
1266 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1267 BackgroundVertex* currentVertex = vertices;
1268 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1270 currentVertex->mPosition = Vector2( -0.5f, d );
1271 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1274 currentVertex->mPosition = Vector2( 0.5f, d );
1275 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1280 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1281 unsigned short indices[ numIndices ];
1283 unsigned short* currentIndex = indices;
1284 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1286 *currentIndex++ = (2 * y);
1287 *currentIndex++ = (2 * y) + 3;
1288 *currentIndex++ = (2 * y) + 1;
1290 *currentIndex++ = (2 * y);
1291 *currentIndex++ = (2 * y) + 2;
1292 *currentIndex++ = (2 * y) + 3;
1295 Dali::Property::Map vertexFormat;
1296 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1297 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1298 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1299 vertexPropertyBuffer.SetData( vertices, numVertices );
1301 // Create the geometry object
1302 mTranslucentGeometry = Dali::Geometry::New();
1303 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1304 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1307 return mTranslucentGeometry;
1308 case Dali::Window::OPAQUE:
1310 if( !mSolidGeometry )
1313 struct BackgroundVertex
1319 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1320 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1323 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1325 Dali::Property::Map vertexFormat;
1326 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1327 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1328 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1329 vertexPropertyBuffer.SetData( vertices, 4 );
1332 // Create the geometry object
1333 mSolidGeometry = Dali::Geometry::New();
1334 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1335 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1338 return mSolidGeometry;
1339 case Dali::Window::TRANSPARENT:
1343 return Dali::Geometry();
1346 void Indicator::SetForegroundImage( Dali::Texture texture )
1348 if( !mForegroundRenderer && texture )
1351 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1353 // Create renderer from geometry and material
1354 Dali::Geometry quad = CreateQuadGeometry();
1355 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1356 // Make sure the foreground stays in front of the background
1357 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1359 // Set blend function
1360 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1361 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1362 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1363 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1365 // Create a texture-set and add to renderer
1367 Dali::TextureSet textureSet = Dali::TextureSet::New();
1368 textureSet.SetTexture( 0u, texture );
1369 mForegroundRenderer.SetTextures( textureSet );
1371 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1373 else if( mForegroundRenderer )
1375 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1376 textureSet.SetTexture( 0u, texture );
1379 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1381 Resize( texture.GetWidth(), texture.GetHeight() );
1385 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1387 if( mObserver != NULL )
1389 mObserver->IndicatorTypeChanged( indicatorType );
1393 void Indicator::DataReceived( void* event )
1395 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1396 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1398 switch( epcEvent->minor )
1402 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1405 mAdaptor->RequestUpdateOnce();
1409 case OP_UPDATE_DONE:
1411 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1412 // epcEvent->response == display buffer #
1413 UpdateImageData( epcEvent->response );
1418 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1419 SetSharedImageInfo( epcEvent );
1424 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1425 SetLockFileInfo( epcEvent );
1430 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1431 LoadSharedImage( epcEvent );
1436 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1437 LoadPixmapImage( epcEvent );
1442 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1444 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1446 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1447 Resize( newSize->w, newSize->h );
1453 int msgDomain = epcEvent->ref;
1454 int msgId = epcEvent->ref_to;
1456 void *msgData = NULL;
1457 int msgDataSize = 0;
1458 msgData = epcEvent->data;
1459 msgDataSize = epcEvent->size;
1461 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1463 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1467 case MSG_ID_INDICATOR_TYPE:
1469 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1470 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1471 OnIndicatorTypeChanged( *indicatorType );
1475 case MSG_ID_INDICATOR_START_ANIMATION:
1477 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1479 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1481 DALI_LOG_ERROR("Message data is incorrect\n");
1485 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1487 if(!CheckVisibleState())
1489 ShowIndicator( animData->duration /* n sec */ );
1500 void Indicator::ConnectionClosed()
1502 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1504 // Will get this callback if the server connection failed to start up.
1505 delete mServerConnection;
1506 mServerConnection = NULL;
1507 mState = DISCONNECTED;
1509 // Attempt to re-connect
1513 bool Indicator::CheckVisibleState()
1515 if( mOrientation == Dali::Window::LANDSCAPE
1516 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1517 || (mVisible == Dali::Window::INVISIBLE)
1518 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1526 void Indicator::ClearSharedFileInfo()
1528 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1530 delete mSharedFileInfo[i].mLock;
1531 mSharedFileInfo[i].mLock = NULL;
1533 delete mSharedFileInfo[i].mSharedFile;
1534 mSharedFileInfo[i].mSharedFile = NULL;
1536 mSharedFileInfo[i].mLockFileName.clear();
1537 mSharedFileInfo[i].mSharedFileName.clear();
1542 * duration can be this
1546 * KEEP_SHOWING = -1,
1550 void Indicator::ShowIndicator(float duration)
1552 if( !mIndicatorAnimation )
1554 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1555 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1558 if(mIsShowing && !EqualsZero(duration))
1560 // If need to show during showing, do nothing.
1561 // In 2nd phase (below) will update timer
1563 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1565 // If need to hide during hiding or hidden already, do nothing
1569 mIndicatorAnimation.Clear();
1571 if( EqualsZero(duration) )
1573 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1577 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1581 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1585 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1588 mIndicatorAnimation.Play();
1589 mIsAnimationPlaying = true;
1596 mShowTimer = Dali::Timer::New(1000 * duration);
1597 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1599 mShowTimer.SetInterval(1000* duration);
1602 if( mVisible == Dali::Window::AUTO )
1604 // check the stage touch
1605 Dali::Stage::GetCurrent().TouchSignal().Connect( this, &Indicator::OnStageTouch );
1610 if(mShowTimer && mShowTimer.IsRunning())
1615 if( mVisible == Dali::Window::AUTO )
1617 // check the stage touch
1618 Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &Indicator::OnStageTouch );
1623 bool Indicator::OnShowTimer()
1625 // after time up, hide indicator
1626 ShowIndicator( HIDE_NOW );
1631 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1633 mIsAnimationPlaying = false;
1634 // once animation is finished and indicator is hidden, take it off stage
1635 if( mObserver != NULL )
1637 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1641 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1643 // Nothing to do, but we still want to consume pan
1646 void Indicator::OnStageTouch(const Dali::TouchData& touchData)
1648 // when stage is touched while indicator is showing temporary, hide it
1649 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1651 switch( touchData.GetState(0) )
1653 case Dali::PointState::DOWN:
1655 // if touch point is inside the indicator, indicator is not hidden
1656 if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
1658 ShowIndicator( HIDE_NOW );
1675 #pragma GCC diagnostic pop