2 * Copyright (c) 2018 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/tizen-wayland/indicator-impl-ecore-wl.h>
22 // Ecore is littered with C style cast
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wold-style-cast"
27 #include <Ecore_Wayland.h>
29 #include <sys/types.h>
34 #include <dali/public-api/images/native-image.h>
35 #include <dali/public-api/events/touch-point.h>
36 #include <dali/public-api/common/stage.h>
37 #include <dali/public-api/images/pixel.h>
39 #include <dali/integration-api/debug.h>
42 #include <dali/internal/adaptor/common/adaptor-impl.h>
43 #include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
44 #include <dali/public-api/adaptor-framework/native-image-source.h>
46 #if defined(DEBUG_ENABLED)
47 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
53 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
54 const float AUTO_INDICATOR_STAY_DURATION( 3.0f ); // 3 seconds
62 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
63 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
65 #define MAKE_SHADER(A)#A
67 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
68 attribute mediump vec2 aPosition;
69 attribute mediump float aAlpha;
70 varying mediump float vAlpha;
71 uniform mediump mat4 uMvpMatrix;
72 uniform mediump vec3 uSize;
76 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
77 vertexPosition = uMvpMatrix * vertexPosition;
80 gl_Position = vertexPosition;
84 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
85 uniform lowp vec4 uColor;
86 varying mediump float vAlpha;
90 gl_FragColor = uColor;
91 gl_FragColor.a *= vAlpha;
95 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
96 attribute mediump vec2 aPosition;\n
97 varying mediump vec2 vTexCoord;\n
98 uniform mediump mat4 uMvpMatrix;\n
99 uniform mediump vec3 uSize;\n
100 uniform mediump vec4 sTextureRect;\n
104 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
105 vTexCoord = aPosition + vec2(0.5);\n
109 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
110 varying mediump vec2 vTexCoord;\n
111 uniform sampler2D sTexture;\n
115 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
119 Dali::Geometry CreateQuadGeometry()
121 Dali::Property::Map quadVertexFormat;
122 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
123 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
125 const float halfQuadSize = .5f;
126 struct QuadVertex { Dali::Vector2 position; };
127 QuadVertex quadVertexData[4] = {
128 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
129 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
130 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
131 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
132 vertexData.SetData(quadVertexData, 4);
134 Dali::Geometry quad = Dali::Geometry::New();
135 quad.AddVertexBuffer( vertexData );
136 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
140 // indicator service name
141 const char* INDICATOR_SERVICE_NAME("elm_indicator");
143 // Copied from ecore_evas_extn_engine.h
157 OP_PROFILE_CHANGE_REQUEST,
158 OP_PROFILE_CHANGE_DONE,
175 // Copied from elm_conform.c
177 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
178 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
179 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
180 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
181 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
182 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
189 struct IpcIndicatorDataAnimation
195 struct IpcDataEvMouseUp
198 Evas_Button_Flags flags;
200 unsigned int timestamp;
201 Evas_Event_Flags event_flags;
203 IpcDataEvMouseUp(unsigned long timestamp)
205 flags(EVAS_BUTTON_NONE),
207 timestamp(static_cast<unsigned int>(timestamp)),
208 event_flags(EVAS_EVENT_FLAG_NONE)
213 struct IpcDataEvMouseDown
216 Evas_Button_Flags flags;
218 unsigned int timestamp;
219 Evas_Event_Flags event_flags;
221 IpcDataEvMouseDown(unsigned long timestamp)
223 flags(EVAS_BUTTON_NONE),
225 timestamp(static_cast<unsigned int>(timestamp)),
226 event_flags(EVAS_EVENT_FLAG_NONE)
231 struct IpcDataEvMouseMove
234 Evas_Button_Flags flags;
236 unsigned int timestamp;
237 Evas_Event_Flags event_flags;
239 IpcDataEvMouseMove(const Dali::Vector2& touchPoint, unsigned long timestamp)
240 : x(static_cast<Evas_Coord>(touchPoint.x)),
241 y(static_cast<Evas_Coord>(touchPoint.y)),
242 flags(EVAS_BUTTON_NONE),
244 timestamp(static_cast<unsigned int>(timestamp)),
245 event_flags(EVAS_EVENT_FLAG_NONE)
250 struct IpcDataEvMouseOut
252 unsigned int timestamp;
254 Evas_Event_Flags event_flags;
256 IpcDataEvMouseOut(unsigned long timestamp)
257 : timestamp(static_cast<unsigned int>(timestamp)),
259 event_flags(EVAS_EVENT_FLAG_NONE)
264 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
266 void SaveIndicatorImage( Dali::NativeImageSourcePtr nativeImageSource )
268 // Save image data to disk in BMP form.
269 static int gFilenameCounter = 0;
270 static const char bmpHeader[] = {
271 0x42, 0x4d, 0x0a, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x7c, 0x00,
273 0xe0, 0x01, 0x00, 0x00, // Width (480)
274 0x1b, 0x00, 0x00, 0x00, // Height ( 27)
275 0x01, 0x00, 0x20, 0x00, 0x03, 0x00,
276 0x00, 0x00, 0x80, 0xca, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
278 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
285 // This is a BMP header with width & height hard-coded in.
286 // The data was first determined by dumping the raw data and inspecting in GIMP, before creating this header data.
287 std::vector<unsigned char> buffer;
290 Dali::Pixel::Format pixelFormat;
291 if( nativeImageSource->GetPixels( buffer, w, h, pixelFormat ) )
293 int imageSize = w * h * 4;
294 std::stringstream fileName;
295 // Give each file an incremental filename.
296 fileName << "/opt/usr/media/Images/out-" << std::setfill( '0' ) << std::setw( 5 ) << gFilenameCounter << ".bmp";
298 std::ofstream outfile( fileName.str().c_str(), std::ofstream::binary );
299 if( outfile.is_open() )
301 DALI_LOG_WARNING( "Saving Indicator Image w:%d, h:%d, %s\n", w, h, fileName.str().c_str() );
303 outfile.write( bmpHeader, sizeof( bmpHeader ) / sizeof( bmpHeader[0] ) ); // Size of the BMP header.
304 outfile.write( (const char*)buffer.data(), imageSize );
310 DALI_LOG_ERROR( "COULD NOT OPEN FOR SAVING: %s\n", fileName.str().c_str() );
317 } // anonymous namespace
326 #if defined(DEBUG_ENABLED)
327 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
330 // Impl to hide EFL implementation.
332 struct IndicatorEcoreWl::Impl
334 enum // operation mode
337 INDICATOR_STAY_WITH_DURATION
343 Impl(IndicatorEcoreWl* indicator)
344 : mIndicator(indicator),
345 mEcoreEventHandler(NULL)
347 #if defined(DALI_PROFILE_MOBILE)
348 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
349 #endif // DALI_PROFILE_MOBILE
357 if ( mEcoreEventHandler )
359 ecore_event_handler_del(mEcoreEventHandler);
363 static void SetIndicatorVisibility( void* data, int operation )
365 IndicatorEcoreWl::Impl* indicatorImpl((IndicatorEcoreWl::Impl*)data);
367 if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
371 if ( operation == INDICATOR_STAY_WITH_DURATION )
373 // if indicator is not showing, INDICATOR_FLICK_DONE is given
374 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
375 !indicatorImpl->mIndicator->mIsShowing )
377 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
380 else if( operation == INDICATOR_HIDE )
382 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
383 indicatorImpl->mIndicator->mIsShowing )
385 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
390 #if defined(DALI_PROFILE_MOBILE)
392 * Called when the Ecore indicator event is received.
394 static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
396 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
397 return ECORE_CALLBACK_PASS_ON;
399 #endif // DALI_PROFILE_MOBILE
402 IndicatorEcoreWl* mIndicator;
403 Ecore_Event_Handler* mEcoreEventHandler;
406 IndicatorEcoreWl::LockFile::LockFile(const std::string filename)
407 : mFilename(filename),
410 mFileDescriptor = open(filename.c_str(), O_RDWR);
411 if( mFileDescriptor == -1 )
415 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
419 IndicatorEcoreWl::LockFile::~LockFile()
421 // Closing file descriptor also unlocks file.
422 if( mFileDescriptor > 0 )
424 close( mFileDescriptor );
428 bool IndicatorEcoreWl::LockFile::Lock()
430 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
433 if( mFileDescriptor > 0 )
435 struct flock filelock;
437 filelock.l_type = F_RDLCK;
438 filelock.l_whence = SEEK_SET;
439 filelock.l_start = 0;
441 if( fcntl( mFileDescriptor, F_SETLKW, &filelock ) == -1 )
444 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
454 DALI_LOG_ERROR( "### Invalid fd ###\n" );
460 void IndicatorEcoreWl::LockFile::Unlock()
462 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
464 if( mFileDescriptor > 0 )
466 struct flock filelock;
468 filelock.l_type = F_UNLCK;
469 filelock.l_whence = SEEK_SET;
470 filelock.l_start = 0;
472 if (fcntl(mFileDescriptor, F_SETLKW, &filelock) == -1)
475 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
480 bool IndicatorEcoreWl::LockFile::RetrieveAndClearErrorStatus()
482 bool error = mErrorThrown;
483 mErrorThrown = false;
487 IndicatorEcoreWl::ScopedLock::ScopedLock(LockFile* lockFile)
488 : mLockFile(lockFile),
493 mLocked = mLockFile->Lock();
497 IndicatorEcoreWl::ScopedLock::~ScopedLock()
505 bool IndicatorEcoreWl::ScopedLock::IsLocked()
510 IndicatorEcoreWl::IndicatorEcoreWl( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
511 : mConnection( this ),
512 mOpacityMode( Dali::Window::OPAQUE ),
513 mState( DISCONNECTED ),
515 mServerConnection( NULL ),
516 mObserver( observer ),
517 mOrientation( orientation ),
520 mVisible( Dali::Window::INVISIBLE ),
522 mIsAnimationPlaying( false ),
523 mCurrentSharedFile( 0 ),
525 mBackgroundVisible( false ),
528 mIndicatorContentActor = Dali::Actor::New();
529 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
530 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
532 // Indicator image handles the touch event including "leave"
533 mIndicatorContentActor.SetLeaveRequired( true );
534 mIndicatorContentActor.TouchSignal().Connect( this, &IndicatorEcoreWl::OnTouch );
535 mIndicatorContentActor.SetColor( Color::BLACK );
537 mIndicatorActor = Dali::Actor::New();
538 mIndicatorActor.Add( mIndicatorContentActor );
540 // Event handler to find out flick down gesture
541 mEventActor = Dali::Actor::New();
542 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
543 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
544 mIndicatorActor.Add( mEventActor );
546 // Attach pan gesture to find flick down during hiding.
547 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
548 // since it consumes the pan gesture in advance.
549 mPanDetector = Dali::PanGestureDetector::New();
550 mPanDetector.DetectedSignal().Connect( this, &IndicatorEcoreWl::OnPan );
551 mPanDetector.Attach( mEventActor );
555 // register indicator to accessibility adaptor
556 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
557 if(accessibilityAdaptor)
559 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
561 // hide the indicator by default
562 mIndicatorActor.SetVisible( false );
564 // create impl to handle ecore event
565 mImpl = new Impl(this);
568 IndicatorEcoreWl::~IndicatorEcoreWl()
578 mEventActor.TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnTouch );
583 void IndicatorEcoreWl::SetAdaptor(Adaptor* adaptor)
586 mIndicatorBuffer->SetAdaptor( adaptor );
589 Dali::Actor IndicatorEcoreWl::GetActor()
591 return mIndicatorActor;
594 void IndicatorEcoreWl::Open( Dali::Window::WindowOrientation orientation )
596 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
598 // Calls from Window should be set up to ensure we are in a
599 // disconnected state before opening a second time.
600 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
602 mOrientation = orientation;
606 // Change background visibility depending on orientation
607 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
609 if( mBackgroundRenderer )
611 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
612 mBackgroundVisible = false;
617 SetOpacityMode( mOpacityMode );
621 void IndicatorEcoreWl::Close()
623 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
625 if( mState == CONNECTED )
628 if( mObserver != NULL )
630 mObserver->IndicatorClosed( this );
634 Dali::Texture emptyTexture;
635 SetForegroundImage( emptyTexture );
638 void IndicatorEcoreWl::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
642 Dali::Geometry geometry = CreateBackgroundGeometry();
645 if( mBackgroundRenderer )
647 if( mBackgroundRenderer.GetGeometry() != geometry )
649 mBackgroundRenderer.SetGeometry( geometry );
654 if( !mBackgroundShader )
656 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
659 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
662 if( !mBackgroundVisible )
664 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
665 mBackgroundVisible = true;
668 else if( mBackgroundRenderer )
670 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
671 mBackgroundVisible = false;
676 void IndicatorEcoreWl::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
678 if ( visibleMode != mVisible || forceUpdate )
680 // If we were previously hidden, then we should update the image data before we display the indicator
681 if ( mVisible == Dali::Window::INVISIBLE )
683 UpdateImageData( mCurrentSharedFile );
686 if ( visibleMode == Dali::Window::INVISIBLE )
688 if (mServerConnection)
690 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
695 mIndicatorActor.SetVisible( true );
697 if( mServerConnection )
699 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
703 mVisible = visibleMode;
706 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
708 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
711 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
713 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
716 ShowIndicator( KEEP_SHOWING );
721 ShowIndicator( HIDE_NOW );
731 bool IndicatorEcoreWl::IsConnected()
733 return ( mState == CONNECTED );
736 bool IndicatorEcoreWl::SendMessage( int messageDomain, int messageId, const void *data, int size )
740 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
748 bool IndicatorEcoreWl::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
750 if( mServerConnection )
752 // Send touch event to indicator server when indicator is showing
753 if( CheckVisibleState() || mIsShowing )
755 switch( touchData.GetState(0) )
757 case Dali::PointState::DOWN:
759 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
760 IpcDataEvMouseDown ipcDown( touchData.GetTime() );
761 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
762 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
764 if( mVisible == Dali::Window::AUTO )
766 // Stop hiding indicator
767 ShowIndicator( KEEP_SHOWING );
772 case Dali::PointState::MOTION:
774 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
775 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
779 case Dali::PointState::UP:
780 case Dali::PointState::INTERRUPTED:
782 IpcDataEvMouseUp ipcUp( touchData.GetTime() );
783 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
785 if( mVisible == Dali::Window::AUTO )
788 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
793 case Dali::TouchPoint::Leave:
795 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
796 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
797 IpcDataEvMouseUp ipcOut( touchData.GetTime() );
798 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
813 bool IndicatorEcoreWl::Connect()
815 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
817 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
819 bool connected = false;
821 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
822 if( mServerConnection )
824 connected = mServerConnection->IsConnected();
827 delete mServerConnection;
828 mServerConnection = NULL;
834 StartReconnectionTimer();
844 void IndicatorEcoreWl::StartReconnectionTimer()
846 if( ! mReconnectTimer )
848 mReconnectTimer = Dali::Timer::New(1000);
849 mConnection.DisconnectAll();
850 mReconnectTimer.TickSignal().Connect( mConnection, &IndicatorEcoreWl::OnReconnectTimer );
852 mReconnectTimer.Start();
855 bool IndicatorEcoreWl::OnReconnectTimer()
859 if( mState == DISCONNECTED )
870 void IndicatorEcoreWl::Disconnect()
872 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
874 mState = DISCONNECTED;
876 delete mServerConnection;
877 mServerConnection = NULL;
879 ClearSharedFileInfo();
882 void IndicatorEcoreWl::Resize( int width, int height )
893 if( mImageWidth != width || mImageHeight != height )
896 mImageHeight = height;
898 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
899 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
900 mEventActor.SetSize(mImageWidth, mImageHeight);
905 void IndicatorEcoreWl::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
907 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
909 // epcEvent->ref == w
910 // epcEvent->ref_to == h
911 // epcEvent->response == buffer num
912 // epcEvent->data = lockfile + nul byte
914 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
915 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
917 int n = epcEvent->response;
919 if( n >= 0 && n < SHARED_FILE_NUMBER )
921 mCurrentSharedFile = n;
923 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
924 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
926 mSharedFileInfo[n].mLockFileName.clear();
928 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
930 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
931 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
936 void IndicatorEcoreWl::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
938 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
940 // epcEvent->ref == shm id
941 // epcEvent->ref_to == shm num
942 // epcEvent->response == buffer num
943 // epcEvent->data = shm ref string + nul byte
945 if ( (epcEvent->data) &&
946 (epcEvent->size > 0) &&
947 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
949 int n = epcEvent->response;
951 if( n >= 0 && n < SHARED_FILE_NUMBER )
953 mCurrentSharedFile = n;
955 mSharedFileInfo[n].mSharedFileName.clear();
957 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
959 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
960 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
962 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
963 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
968 void IndicatorEcoreWl::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
970 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
972 // epcEvent->ref == alpha
973 // epcEvent->ref_to == sys
974 // epcEvent->response == buffer num
976 int n = epcEvent->response;
978 if( n >= 0 && n < SHARED_FILE_NUMBER )
980 mCurrentSharedFile = n;
982 delete mSharedFileInfo[n].mSharedFile;
983 mSharedFileInfo[n].mSharedFile = NULL;
985 delete mSharedFileInfo[n].mLock;
986 mSharedFileInfo[n].mLock = NULL;
988 std::stringstream sharedFileID;
989 std::stringstream sharedFileNumber;
991 sharedFileID << mSharedFileInfo[n].mSharedFileID;
992 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
994 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
996 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
998 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
999 if( mSharedFileInfo[n].mSharedFile != NULL )
1001 mSharedFileInfo[n].mLock = new IndicatorEcoreWl::LockFile( mSharedFileInfo[n].mLockFileName );
1002 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1004 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1008 CreateNewImage( n );
1015 void IndicatorEcoreWl::UpdateTopMargin()
1017 int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1018 if (mTopMargin != newMargin)
1020 mTopMargin = newMargin;
1021 mAdaptor->IndicatorSizeChanged( mTopMargin );
1025 void IndicatorEcoreWl::UpdateVisibility()
1027 if( CheckVisibleState() )
1029 // set default indicator type (enable the quick panel)
1030 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1034 // set default indicator type (disable the quick panel)
1035 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1040 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1043 SetVisible(mVisible, true);
1046 void IndicatorEcoreWl::UpdateImageData( int bufferNumber )
1048 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1050 if( mState == CONNECTED && mVisible )
1052 // not sure we can skip it when mIsShowing is false
1053 CopyToBuffer( bufferNumber );
1057 bool IndicatorEcoreWl::CopyToBuffer( int bufferNumber )
1059 bool success = false;
1061 if( mSharedFileInfo[bufferNumber].mLock )
1063 IndicatorEcoreWl::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1064 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1068 else if( scopedLock.IsLocked() )
1070 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1071 size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1073 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1075 mAdaptor->RequestUpdateOnce();
1084 void IndicatorEcoreWl::CreateNewImage( int bufferNumber )
1086 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1087 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1088 bool success = false;
1090 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1092 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1095 SetForegroundImage( texture );
1102 DALI_LOG_WARNING("### Cannot create indicator image ###\n");
1106 Dali::Geometry IndicatorEcoreWl::CreateBackgroundGeometry()
1108 switch( mOpacityMode )
1110 case Dali::Window::TRANSLUCENT:
1111 if( !mTranslucentGeometry )
1113 // Construct 5 interval mesh
1127 struct BackgroundVertex
1133 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1134 BackgroundVertex vertices[ numVertices ];
1137 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1138 BackgroundVertex* currentVertex = vertices;
1139 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1141 currentVertex->mPosition = Vector2( -0.5f, d );
1142 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1145 currentVertex->mPosition = Vector2( 0.5f, d );
1146 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1151 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1152 unsigned short indices[ numIndices ];
1154 unsigned short* currentIndex = indices;
1155 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1157 *currentIndex++ = (2 * y);
1158 *currentIndex++ = (2 * y) + 3;
1159 *currentIndex++ = (2 * y) + 1;
1161 *currentIndex++ = (2 * y);
1162 *currentIndex++ = (2 * y) + 2;
1163 *currentIndex++ = (2 * y) + 3;
1166 Dali::Property::Map vertexFormat;
1167 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1168 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1169 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1170 vertexPropertyBuffer.SetData( vertices, numVertices );
1172 // Create the geometry object
1173 mTranslucentGeometry = Dali::Geometry::New();
1174 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1175 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1178 return mTranslucentGeometry;
1179 case Dali::Window::OPAQUE:
1181 if( !mSolidGeometry )
1184 struct BackgroundVertex
1190 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1191 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1194 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1196 Dali::Property::Map vertexFormat;
1197 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1198 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1199 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1200 vertexPropertyBuffer.SetData( vertices, 4 );
1203 // Create the geometry object
1204 mSolidGeometry = Dali::Geometry::New();
1205 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1206 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1209 return mSolidGeometry;
1210 case Dali::Window::TRANSPARENT:
1214 return Dali::Geometry();
1217 void IndicatorEcoreWl::SetForegroundImage( Dali::Texture texture )
1219 if( !mForegroundRenderer && texture )
1222 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1224 // Create renderer from geometry and material
1225 Dali::Geometry quad = CreateQuadGeometry();
1226 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1227 // Make sure the foreground stays in front of the background
1228 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1230 // Set blend function
1231 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1232 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1233 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1234 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1236 // Create a texture-set and add to renderer
1238 Dali::TextureSet textureSet = Dali::TextureSet::New();
1239 textureSet.SetTexture( 0u, texture );
1240 mForegroundRenderer.SetTextures( textureSet );
1242 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1244 else if( mForegroundRenderer )
1246 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1247 textureSet.SetTexture( 0u, texture );
1250 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1252 Resize( texture.GetWidth(), texture.GetHeight() );
1256 void IndicatorEcoreWl::OnIndicatorTypeChanged( Type indicatorType )
1258 if( mObserver != NULL )
1260 mObserver->IndicatorTypeChanged( indicatorType );
1264 void IndicatorEcoreWl::DataReceived( void* event )
1266 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1267 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1269 switch( epcEvent->minor )
1273 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1276 mAdaptor->RequestUpdateOnce();
1280 case OP_UPDATE_DONE:
1282 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1283 // epcEvent->response == display buffer #
1284 UpdateImageData( epcEvent->response );
1289 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1290 SetSharedImageInfo( epcEvent );
1295 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1296 SetLockFileInfo( epcEvent );
1301 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1302 LoadSharedImage( epcEvent );
1307 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1309 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1311 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1312 Resize( newSize->w, newSize->h );
1318 int msgDomain = epcEvent->ref;
1319 int msgId = epcEvent->ref_to;
1321 void *msgData = NULL;
1322 int msgDataSize = 0;
1323 msgData = epcEvent->data;
1324 msgDataSize = epcEvent->size;
1326 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1328 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1332 case MSG_ID_INDICATOR_TYPE:
1334 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1335 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1336 OnIndicatorTypeChanged( *indicatorType );
1340 case MSG_ID_INDICATOR_START_ANIMATION:
1342 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1344 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1346 DALI_LOG_ERROR("Message data is incorrect\n");
1350 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1352 if(!CheckVisibleState())
1354 ShowIndicator( animData->duration /* n sec */ );
1365 void IndicatorEcoreWl::ConnectionClosed()
1367 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1369 // Will get this callback if the server connection failed to start up.
1370 delete mServerConnection;
1371 mServerConnection = NULL;
1372 mState = DISCONNECTED;
1374 // Attempt to re-connect
1378 bool IndicatorEcoreWl::CheckVisibleState()
1380 if( mOrientation == Dali::Window::LANDSCAPE
1381 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1382 || (mVisible == Dali::Window::INVISIBLE)
1383 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1391 void IndicatorEcoreWl::ClearSharedFileInfo()
1393 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1395 delete mSharedFileInfo[i].mLock;
1396 mSharedFileInfo[i].mLock = NULL;
1398 delete mSharedFileInfo[i].mSharedFile;
1399 mSharedFileInfo[i].mSharedFile = NULL;
1401 mSharedFileInfo[i].mLockFileName.clear();
1402 mSharedFileInfo[i].mSharedFileName.clear();
1407 * duration can be this
1411 * KEEP_SHOWING = -1,
1415 void IndicatorEcoreWl::ShowIndicator(float duration)
1417 if( !mIndicatorAnimation )
1419 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1420 mIndicatorAnimation.FinishedSignal().Connect(this, &IndicatorEcoreWl::OnAnimationFinished);
1423 if(mIsShowing && !EqualsZero(duration))
1425 // If need to show during showing, do nothing.
1426 // In 2nd phase (below) will update timer
1428 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1430 // If need to hide during hiding or hidden already, do nothing
1434 mIndicatorAnimation.Clear();
1436 if( EqualsZero(duration) )
1438 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1442 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1446 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1450 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1453 mIndicatorAnimation.Play();
1454 mIsAnimationPlaying = true;
1461 mShowTimer = Dali::Timer::New(1000 * duration);
1462 mShowTimer.TickSignal().Connect(this, &IndicatorEcoreWl::OnShowTimer);
1464 mShowTimer.SetInterval(1000* duration);
1467 if( mVisible == Dali::Window::AUTO )
1469 // check the stage touch
1470 Dali::Stage::GetCurrent().TouchSignal().Connect( this, &IndicatorEcoreWl::OnStageTouch );
1475 if(mShowTimer && mShowTimer.IsRunning())
1480 if( mVisible == Dali::Window::AUTO )
1482 // check the stage touch
1483 Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnStageTouch );
1488 bool IndicatorEcoreWl::OnShowTimer()
1490 // after time up, hide indicator
1491 ShowIndicator( HIDE_NOW );
1496 void IndicatorEcoreWl::OnAnimationFinished(Dali::Animation& animation)
1498 mIsAnimationPlaying = false;
1499 // once animation is finished and indicator is hidden, take it off stage
1500 if( mObserver != NULL )
1502 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1506 void IndicatorEcoreWl::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1508 // Nothing to do, but we still want to consume pan
1511 void IndicatorEcoreWl::OnStageTouch(const Dali::TouchData& touchData)
1513 // when stage is touched while indicator is showing temporary, hide it
1514 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1516 switch( touchData.GetState(0) )
1518 case Dali::PointState::DOWN:
1520 // if touch point is inside the indicator, indicator is not hidden
1521 if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
1523 ShowIndicator( HIDE_NOW );
1540 #pragma GCC diagnostic pop