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"
28 #include <sys/types.h>
33 #include <dali/public-api/images/native-image.h>
34 #include <dali/public-api/events/touch-point.h>
35 #include <dali/public-api/common/stage.h>
36 #include <dali/public-api/images/pixel.h>
38 #include <dali/integration-api/debug.h>
41 #include <dali/internal/adaptor/common/adaptor-impl.h>
42 #include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
43 #include <dali/public-api/adaptor-framework/native-image-source.h>
45 #if defined(DEBUG_ENABLED)
46 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
52 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
53 const float AUTO_INDICATOR_STAY_DURATION( 3.0f ); // 3 seconds
61 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
62 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
64 #define MAKE_SHADER(A)#A
66 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
67 attribute mediump vec2 aPosition;
68 attribute mediump float aAlpha;
69 varying mediump float vAlpha;
70 uniform mediump mat4 uMvpMatrix;
71 uniform mediump vec3 uSize;
75 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
76 vertexPosition = uMvpMatrix * vertexPosition;
79 gl_Position = vertexPosition;
83 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
84 uniform lowp vec4 uColor;
85 varying mediump float vAlpha;
89 gl_FragColor = uColor;
90 gl_FragColor.a *= vAlpha;
94 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
95 attribute mediump vec2 aPosition;\n
96 varying mediump vec2 vTexCoord;\n
97 uniform mediump mat4 uMvpMatrix;\n
98 uniform mediump vec3 uSize;\n
99 uniform mediump vec4 sTextureRect;\n
103 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
104 vTexCoord = aPosition + vec2(0.5);\n
108 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
109 varying mediump vec2 vTexCoord;\n
110 uniform sampler2D sTexture;\n
114 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
118 Dali::Geometry CreateQuadGeometry()
120 Dali::Property::Map quadVertexFormat;
121 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
122 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
124 const float halfQuadSize = .5f;
125 struct QuadVertex { Dali::Vector2 position; };
126 QuadVertex quadVertexData[4] = {
127 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
128 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
129 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
130 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
131 vertexData.SetData(quadVertexData, 4);
133 Dali::Geometry quad = Dali::Geometry::New();
134 quad.AddVertexBuffer( vertexData );
135 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
139 // indicator service name
140 const char* INDICATOR_SERVICE_NAME("elm_indicator");
142 // Copied from ecore_evas_extn_engine.h
156 OP_PROFILE_CHANGE_REQUEST,
157 OP_PROFILE_CHANGE_DONE,
174 // Copied from elm_conform.c
176 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
177 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
178 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
179 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
180 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
181 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
188 struct IpcIndicatorDataAnimation
194 struct IpcDataEvMouseUp
197 Evas_Button_Flags flags;
199 unsigned int timestamp;
200 Evas_Event_Flags event_flags;
202 IpcDataEvMouseUp(unsigned long timestamp)
204 flags(EVAS_BUTTON_NONE),
206 timestamp(static_cast<unsigned int>(timestamp)),
207 event_flags(EVAS_EVENT_FLAG_NONE)
212 struct IpcDataEvMouseDown
215 Evas_Button_Flags flags;
217 unsigned int timestamp;
218 Evas_Event_Flags event_flags;
220 IpcDataEvMouseDown(unsigned long timestamp)
222 flags(EVAS_BUTTON_NONE),
224 timestamp(static_cast<unsigned int>(timestamp)),
225 event_flags(EVAS_EVENT_FLAG_NONE)
230 struct IpcDataEvMouseMove
233 Evas_Button_Flags flags;
235 unsigned int timestamp;
236 Evas_Event_Flags event_flags;
238 IpcDataEvMouseMove(const Dali::Vector2& touchPoint, unsigned long timestamp)
239 : x(static_cast<Evas_Coord>(touchPoint.x)),
240 y(static_cast<Evas_Coord>(touchPoint.y)),
241 flags(EVAS_BUTTON_NONE),
243 timestamp(static_cast<unsigned int>(timestamp)),
244 event_flags(EVAS_EVENT_FLAG_NONE)
249 struct IpcDataEvMouseOut
251 unsigned int timestamp;
253 Evas_Event_Flags event_flags;
255 IpcDataEvMouseOut(unsigned long timestamp)
256 : timestamp(static_cast<unsigned int>(timestamp)),
258 event_flags(EVAS_EVENT_FLAG_NONE)
263 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
265 void SaveIndicatorImage( Dali::NativeImageSourcePtr nativeImageSource )
267 // Save image data to disk in BMP form.
268 static int gFilenameCounter = 0;
269 static const char bmpHeader[] = {
270 0x42, 0x4d, 0x0a, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x7c, 0x00,
272 0xe0, 0x01, 0x00, 0x00, // Width (480)
273 0x1b, 0x00, 0x00, 0x00, // Height ( 27)
274 0x01, 0x00, 0x20, 0x00, 0x03, 0x00,
275 0x00, 0x00, 0x80, 0xca, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
277 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
284 // This is a BMP header with width & height hard-coded in.
285 // The data was first determined by dumping the raw data and inspecting in GIMP, before creating this header data.
286 std::vector<unsigned char> buffer;
289 Dali::Pixel::Format pixelFormat;
290 if( nativeImageSource->GetPixels( buffer, w, h, pixelFormat ) )
292 int imageSize = w * h * 4;
293 std::stringstream fileName;
294 // Give each file an incremental filename.
295 fileName << "/opt/usr/media/Images/out-" << std::setfill( '0' ) << std::setw( 5 ) << gFilenameCounter << ".bmp";
297 std::ofstream outfile( fileName.str().c_str(), std::ofstream::binary );
298 if( outfile.is_open() )
300 DALI_LOG_WARNING( "Saving Indicator Image w:%d, h:%d, %s\n", w, h, fileName.str().c_str() );
302 outfile.write( bmpHeader, sizeof( bmpHeader ) / sizeof( bmpHeader[0] ) ); // Size of the BMP header.
303 outfile.write( (const char*)buffer.data(), imageSize );
309 DALI_LOG_ERROR( "COULD NOT OPEN FOR SAVING: %s\n", fileName.str().c_str() );
316 } // anonymous namespace
325 #if defined(DEBUG_ENABLED)
326 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
329 IndicatorEcoreWl::LockFile::LockFile(const std::string filename)
330 : mFilename(filename),
333 mFileDescriptor = open(filename.c_str(), O_RDWR);
334 if( mFileDescriptor == -1 )
338 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
342 IndicatorEcoreWl::LockFile::~LockFile()
344 // Closing file descriptor also unlocks file.
345 if( mFileDescriptor > 0 )
347 close( mFileDescriptor );
351 bool IndicatorEcoreWl::LockFile::Lock()
353 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
356 if( mFileDescriptor > 0 )
358 struct flock filelock;
360 filelock.l_type = F_RDLCK;
361 filelock.l_whence = SEEK_SET;
362 filelock.l_start = 0;
364 if( fcntl( mFileDescriptor, F_SETLKW, &filelock ) == -1 )
367 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
377 DALI_LOG_ERROR( "### Invalid fd ###\n" );
383 void IndicatorEcoreWl::LockFile::Unlock()
385 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
387 if( mFileDescriptor > 0 )
389 struct flock filelock;
391 filelock.l_type = F_UNLCK;
392 filelock.l_whence = SEEK_SET;
393 filelock.l_start = 0;
395 if (fcntl(mFileDescriptor, F_SETLKW, &filelock) == -1)
398 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
403 bool IndicatorEcoreWl::LockFile::RetrieveAndClearErrorStatus()
405 bool error = mErrorThrown;
406 mErrorThrown = false;
410 IndicatorEcoreWl::ScopedLock::ScopedLock(LockFile* lockFile)
411 : mLockFile(lockFile),
416 mLocked = mLockFile->Lock();
420 IndicatorEcoreWl::ScopedLock::~ScopedLock()
428 bool IndicatorEcoreWl::ScopedLock::IsLocked()
433 IndicatorEcoreWl::IndicatorEcoreWl( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
434 : mConnection( this ),
435 mOpacityMode( Dali::Window::OPAQUE ),
436 mState( DISCONNECTED ),
438 mServerConnection( NULL ),
439 mObserver( observer ),
440 mOrientation( orientation ),
443 mVisible( Dali::Window::INVISIBLE ),
445 mIsAnimationPlaying( false ),
446 mCurrentSharedFile( 0 ),
447 mBackgroundVisible( false )
449 mIndicatorContentActor = Dali::Actor::New();
450 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
451 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
453 // Indicator image handles the touch event including "leave"
454 mIndicatorContentActor.SetLeaveRequired( true );
455 mIndicatorContentActor.TouchSignal().Connect( this, &IndicatorEcoreWl::OnTouch );
456 mIndicatorContentActor.SetColor( Color::BLACK );
458 mIndicatorActor = Dali::Actor::New();
459 mIndicatorActor.Add( mIndicatorContentActor );
461 // Event handler to find out flick down gesture
462 mEventActor = Dali::Actor::New();
463 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
464 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
465 mIndicatorActor.Add( mEventActor );
467 // Attach pan gesture to find flick down during hiding.
468 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
469 // since it consumes the pan gesture in advance.
470 mPanDetector = Dali::PanGestureDetector::New();
471 mPanDetector.DetectedSignal().Connect( this, &IndicatorEcoreWl::OnPan );
472 mPanDetector.Attach( mEventActor );
476 // register indicator to accessibility adaptor
477 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
478 if(accessibilityAdaptor)
480 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
482 // hide the indicator by default
483 mIndicatorActor.SetVisible( false );
486 IndicatorEcoreWl::~IndicatorEcoreWl()
490 mEventActor.TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnTouch );
495 void IndicatorEcoreWl::SetAdaptor(Adaptor* adaptor)
498 mIndicatorBuffer->SetAdaptor( adaptor );
501 Dali::Actor IndicatorEcoreWl::GetActor()
503 return mIndicatorActor;
506 void IndicatorEcoreWl::Open( Dali::Window::WindowOrientation orientation )
508 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
510 // Calls from Window should be set up to ensure we are in a
511 // disconnected state before opening a second time.
512 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
514 mOrientation = orientation;
518 // Change background visibility depending on orientation
519 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
521 if( mBackgroundRenderer )
523 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
524 mBackgroundVisible = false;
529 SetOpacityMode( mOpacityMode );
533 void IndicatorEcoreWl::Close()
535 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
537 if( mState == CONNECTED )
540 if( mObserver != NULL )
542 mObserver->IndicatorClosed( this );
546 Dali::Texture emptyTexture;
547 SetForegroundImage( emptyTexture );
550 void IndicatorEcoreWl::Flicked()
552 // if indicator is not showing, INDICATOR_FLICK_DONE is given
553 if( mVisible == Dali::Window::AUTO && !mIsShowing )
555 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
559 void IndicatorEcoreWl::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
563 Dali::Geometry geometry = CreateBackgroundGeometry();
566 if( mBackgroundRenderer )
568 if( mBackgroundRenderer.GetGeometry() != geometry )
570 mBackgroundRenderer.SetGeometry( geometry );
575 if( !mBackgroundShader )
577 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
580 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
583 if( !mBackgroundVisible )
585 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
586 mBackgroundVisible = true;
589 else if( mBackgroundRenderer )
591 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
592 mBackgroundVisible = false;
596 void IndicatorEcoreWl::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
598 if ( visibleMode != mVisible || forceUpdate )
600 // If we were previously hidden, then we should update the image data before we display the indicator
601 if ( mVisible == Dali::Window::INVISIBLE )
603 UpdateImageData( mCurrentSharedFile );
606 if ( visibleMode == Dali::Window::INVISIBLE )
608 if (mServerConnection)
610 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
615 mIndicatorActor.SetVisible( true );
617 if( mServerConnection )
619 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
623 mVisible = visibleMode;
625 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
627 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
630 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
632 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
635 ShowIndicator( KEEP_SHOWING );
640 ShowIndicator( HIDE_NOW );
650 bool IndicatorEcoreWl::IsConnected()
652 return ( mState == CONNECTED );
655 bool IndicatorEcoreWl::SendMessage( int messageDomain, int messageId, const void *data, int size )
659 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
667 bool IndicatorEcoreWl::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
669 if( mServerConnection )
671 // Send touch event to indicator server when indicator is showing
672 if( CheckVisibleState() || mIsShowing )
674 switch( touchData.GetState(0) )
676 case Dali::PointState::DOWN:
678 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
679 IpcDataEvMouseDown ipcDown( touchData.GetTime() );
680 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
681 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
683 if( mVisible == Dali::Window::AUTO )
685 // Stop hiding indicator
686 ShowIndicator( KEEP_SHOWING );
691 case Dali::PointState::MOTION:
693 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
694 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
698 case Dali::PointState::UP:
699 case Dali::PointState::INTERRUPTED:
701 IpcDataEvMouseUp ipcUp( touchData.GetTime() );
702 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
704 if( mVisible == Dali::Window::AUTO )
707 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
712 case Dali::TouchPoint::Leave:
714 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
715 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
716 IpcDataEvMouseUp ipcOut( touchData.GetTime() );
717 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
732 bool IndicatorEcoreWl::Connect()
734 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
736 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
738 bool connected = false;
740 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
741 if( mServerConnection )
743 connected = mServerConnection->IsConnected();
746 delete mServerConnection;
747 mServerConnection = NULL;
753 StartReconnectionTimer();
763 void IndicatorEcoreWl::StartReconnectionTimer()
765 if( ! mReconnectTimer )
767 mReconnectTimer = Dali::Timer::New(1000);
768 mConnection.DisconnectAll();
769 mReconnectTimer.TickSignal().Connect( mConnection, &IndicatorEcoreWl::OnReconnectTimer );
771 mReconnectTimer.Start();
774 bool IndicatorEcoreWl::OnReconnectTimer()
778 if( mState == DISCONNECTED )
789 void IndicatorEcoreWl::Disconnect()
791 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
793 mState = DISCONNECTED;
795 delete mServerConnection;
796 mServerConnection = NULL;
798 ClearSharedFileInfo();
801 void IndicatorEcoreWl::Resize( int width, int height )
812 if( mImageWidth != width || mImageHeight != height )
815 mImageHeight = height;
817 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
818 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
819 mEventActor.SetSize(mImageWidth, mImageHeight);
823 void IndicatorEcoreWl::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
825 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
827 // epcEvent->ref == w
828 // epcEvent->ref_to == h
829 // epcEvent->response == buffer num
830 // epcEvent->data = lockfile + nul byte
832 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
833 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
835 int n = epcEvent->response;
837 if( n >= 0 && n < SHARED_FILE_NUMBER )
839 mCurrentSharedFile = n;
841 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
842 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
844 mSharedFileInfo[n].mLockFileName.clear();
846 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
848 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
849 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
854 void IndicatorEcoreWl::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
856 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
858 // epcEvent->ref == shm id
859 // epcEvent->ref_to == shm num
860 // epcEvent->response == buffer num
861 // epcEvent->data = shm ref string + nul byte
863 if ( (epcEvent->data) &&
864 (epcEvent->size > 0) &&
865 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
867 int n = epcEvent->response;
869 if( n >= 0 && n < SHARED_FILE_NUMBER )
871 mCurrentSharedFile = n;
873 mSharedFileInfo[n].mSharedFileName.clear();
875 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
877 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
878 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
880 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
881 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
886 void IndicatorEcoreWl::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
888 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
890 // epcEvent->ref == alpha
891 // epcEvent->ref_to == sys
892 // epcEvent->response == buffer num
894 int n = epcEvent->response;
896 if( n >= 0 && n < SHARED_FILE_NUMBER )
898 mCurrentSharedFile = n;
900 delete mSharedFileInfo[n].mSharedFile;
901 mSharedFileInfo[n].mSharedFile = NULL;
903 delete mSharedFileInfo[n].mLock;
904 mSharedFileInfo[n].mLock = NULL;
906 std::stringstream sharedFileID;
907 std::stringstream sharedFileNumber;
909 sharedFileID << mSharedFileInfo[n].mSharedFileID;
910 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
912 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
914 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
916 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
917 if( mSharedFileInfo[n].mSharedFile != NULL )
919 mSharedFileInfo[n].mLock = new IndicatorEcoreWl::LockFile( mSharedFileInfo[n].mLockFileName );
920 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
922 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
933 void IndicatorEcoreWl::UpdateVisibility()
935 if( CheckVisibleState() )
937 // set default indicator type (enable the quick panel)
938 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
942 // set default indicator type (disable the quick panel)
943 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
948 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
951 SetVisible(mVisible, true);
954 void IndicatorEcoreWl::UpdateImageData( int bufferNumber )
956 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
958 if( mState == CONNECTED && mVisible )
960 // not sure we can skip it when mIsShowing is false
961 CopyToBuffer( bufferNumber );
965 bool IndicatorEcoreWl::CopyToBuffer( int bufferNumber )
967 bool success = false;
969 if( mSharedFileInfo[bufferNumber].mLock )
971 IndicatorEcoreWl::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
972 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
976 else if( scopedLock.IsLocked() )
978 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
979 size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
981 if( mIndicatorBuffer->UpdatePixels( src, size ) )
983 mAdaptor->RequestUpdateOnce();
992 void IndicatorEcoreWl::CreateNewImage( int bufferNumber )
994 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
995 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
996 bool success = false;
998 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1000 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1003 SetForegroundImage( texture );
1010 DALI_LOG_WARNING("### Cannot create indicator image ###\n");
1014 Dali::Geometry IndicatorEcoreWl::CreateBackgroundGeometry()
1016 switch( mOpacityMode )
1018 case Dali::Window::TRANSLUCENT:
1019 if( !mTranslucentGeometry )
1021 // Construct 5 interval mesh
1035 struct BackgroundVertex
1041 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1042 BackgroundVertex vertices[ numVertices ];
1045 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1046 BackgroundVertex* currentVertex = vertices;
1047 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1049 currentVertex->mPosition = Vector2( -0.5f, d );
1050 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1053 currentVertex->mPosition = Vector2( 0.5f, d );
1054 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1059 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1060 unsigned short indices[ numIndices ];
1062 unsigned short* currentIndex = indices;
1063 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1065 *currentIndex++ = (2 * y);
1066 *currentIndex++ = (2 * y) + 3;
1067 *currentIndex++ = (2 * y) + 1;
1069 *currentIndex++ = (2 * y);
1070 *currentIndex++ = (2 * y) + 2;
1071 *currentIndex++ = (2 * y) + 3;
1074 Dali::Property::Map vertexFormat;
1075 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1076 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1077 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1078 vertexPropertyBuffer.SetData( vertices, numVertices );
1080 // Create the geometry object
1081 mTranslucentGeometry = Dali::Geometry::New();
1082 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1083 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1086 return mTranslucentGeometry;
1087 case Dali::Window::OPAQUE:
1089 if( !mSolidGeometry )
1092 struct BackgroundVertex
1098 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1099 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1102 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1104 Dali::Property::Map vertexFormat;
1105 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1106 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1107 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1108 vertexPropertyBuffer.SetData( vertices, 4 );
1111 // Create the geometry object
1112 mSolidGeometry = Dali::Geometry::New();
1113 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1114 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1117 return mSolidGeometry;
1118 case Dali::Window::TRANSPARENT:
1122 return Dali::Geometry();
1125 void IndicatorEcoreWl::SetForegroundImage( Dali::Texture texture )
1127 if( !mForegroundRenderer && texture )
1130 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1132 // Create renderer from geometry and material
1133 Dali::Geometry quad = CreateQuadGeometry();
1134 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1135 // Make sure the foreground stays in front of the background
1136 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1138 // Set blend function
1139 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1140 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1141 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1142 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1144 // Create a texture-set and add to renderer
1146 Dali::TextureSet textureSet = Dali::TextureSet::New();
1147 textureSet.SetTexture( 0u, texture );
1148 mForegroundRenderer.SetTextures( textureSet );
1150 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1152 else if( mForegroundRenderer )
1154 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1155 textureSet.SetTexture( 0u, texture );
1158 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1160 Resize( texture.GetWidth(), texture.GetHeight() );
1164 void IndicatorEcoreWl::OnIndicatorTypeChanged( Type indicatorType )
1166 if( mObserver != NULL )
1168 mObserver->IndicatorTypeChanged( indicatorType );
1172 void IndicatorEcoreWl::DataReceived( void* event )
1174 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1175 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1177 switch( epcEvent->minor )
1181 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1184 mAdaptor->RequestUpdateOnce();
1188 case OP_UPDATE_DONE:
1190 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1191 // epcEvent->response == display buffer #
1192 UpdateImageData( epcEvent->response );
1197 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1198 SetSharedImageInfo( epcEvent );
1203 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1204 SetLockFileInfo( epcEvent );
1209 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1210 LoadSharedImage( epcEvent );
1215 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1217 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1219 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1220 Resize( newSize->w, newSize->h );
1226 int msgDomain = epcEvent->ref;
1227 int msgId = epcEvent->ref_to;
1229 void *msgData = NULL;
1230 int msgDataSize = 0;
1231 msgData = epcEvent->data;
1232 msgDataSize = epcEvent->size;
1234 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1236 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1240 case MSG_ID_INDICATOR_TYPE:
1242 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1243 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1244 OnIndicatorTypeChanged( *indicatorType );
1248 case MSG_ID_INDICATOR_START_ANIMATION:
1250 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1252 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1254 DALI_LOG_ERROR("Message data is incorrect\n");
1258 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1260 if(!CheckVisibleState())
1262 ShowIndicator( animData->duration /* n sec */ );
1273 void IndicatorEcoreWl::ConnectionClosed()
1275 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1277 // Will get this callback if the server connection failed to start up.
1278 delete mServerConnection;
1279 mServerConnection = NULL;
1280 mState = DISCONNECTED;
1282 // Attempt to re-connect
1286 bool IndicatorEcoreWl::CheckVisibleState()
1288 if( mOrientation == Dali::Window::LANDSCAPE
1289 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1290 || (mVisible == Dali::Window::INVISIBLE)
1291 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1299 void IndicatorEcoreWl::ClearSharedFileInfo()
1301 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1303 delete mSharedFileInfo[i].mLock;
1304 mSharedFileInfo[i].mLock = NULL;
1306 delete mSharedFileInfo[i].mSharedFile;
1307 mSharedFileInfo[i].mSharedFile = NULL;
1309 mSharedFileInfo[i].mLockFileName.clear();
1310 mSharedFileInfo[i].mSharedFileName.clear();
1315 * duration can be this
1319 * KEEP_SHOWING = -1,
1323 void IndicatorEcoreWl::ShowIndicator(float duration)
1325 if( !mIndicatorAnimation )
1327 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1328 mIndicatorAnimation.FinishedSignal().Connect(this, &IndicatorEcoreWl::OnAnimationFinished);
1331 if(mIsShowing && !EqualsZero(duration))
1333 // If need to show during showing, do nothing.
1334 // In 2nd phase (below) will update timer
1336 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1338 // If need to hide during hiding or hidden already, do nothing
1342 mIndicatorAnimation.Clear();
1344 if( EqualsZero(duration) )
1346 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1350 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1354 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1358 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1361 mIndicatorAnimation.Play();
1362 mIsAnimationPlaying = true;
1369 mShowTimer = Dali::Timer::New(1000 * duration);
1370 mShowTimer.TickSignal().Connect(this, &IndicatorEcoreWl::OnShowTimer);
1372 mShowTimer.SetInterval(1000* duration);
1375 if( mVisible == Dali::Window::AUTO )
1377 // check the stage touch
1378 Dali::Stage::GetCurrent().TouchSignal().Connect( this, &IndicatorEcoreWl::OnStageTouch );
1383 if(mShowTimer && mShowTimer.IsRunning())
1388 if( mVisible == Dali::Window::AUTO )
1390 // check the stage touch
1391 Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnStageTouch );
1396 bool IndicatorEcoreWl::OnShowTimer()
1398 // after time up, hide indicator
1399 ShowIndicator( HIDE_NOW );
1404 void IndicatorEcoreWl::OnAnimationFinished(Dali::Animation& animation)
1406 mIsAnimationPlaying = false;
1407 // once animation is finished and indicator is hidden, take it off stage
1408 if( mObserver != NULL )
1410 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1414 void IndicatorEcoreWl::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1416 // Nothing to do, but we still want to consume pan
1419 void IndicatorEcoreWl::OnStageTouch(const Dali::TouchData& touchData)
1421 // when stage is touched while indicator is showing temporary, hide it
1422 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1424 switch( touchData.GetState(0) )
1426 case Dali::PointState::DOWN:
1428 // if touch point is inside the indicator, indicator is not hidden
1429 if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
1431 ShowIndicator( HIDE_NOW );
1448 #pragma GCC diagnostic pop