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 ),
450 mIndicatorContentActor = Dali::Actor::New();
451 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
452 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
454 // Indicator image handles the touch event including "leave"
455 mIndicatorContentActor.SetLeaveRequired( true );
456 mIndicatorContentActor.TouchSignal().Connect( this, &IndicatorEcoreWl::OnTouch );
457 mIndicatorContentActor.SetColor( Color::BLACK );
459 mIndicatorActor = Dali::Actor::New();
460 mIndicatorActor.Add( mIndicatorContentActor );
462 // Event handler to find out flick down gesture
463 mEventActor = Dali::Actor::New();
464 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
465 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
466 mIndicatorActor.Add( mEventActor );
468 // Attach pan gesture to find flick down during hiding.
469 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
470 // since it consumes the pan gesture in advance.
471 mPanDetector = Dali::PanGestureDetector::New();
472 mPanDetector.DetectedSignal().Connect( this, &IndicatorEcoreWl::OnPan );
473 mPanDetector.Attach( mEventActor );
477 // register indicator to accessibility adaptor
478 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
479 if(accessibilityAdaptor)
481 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
483 // hide the indicator by default
484 mIndicatorActor.SetVisible( false );
487 IndicatorEcoreWl::~IndicatorEcoreWl()
491 mEventActor.TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnTouch );
496 void IndicatorEcoreWl::SetAdaptor(Adaptor* adaptor)
499 mIndicatorBuffer->SetAdaptor( adaptor );
502 Dali::Actor IndicatorEcoreWl::GetActor()
504 return mIndicatorActor;
507 void IndicatorEcoreWl::Open( Dali::Window::WindowOrientation orientation )
509 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
511 // Calls from Window should be set up to ensure we are in a
512 // disconnected state before opening a second time.
513 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
515 mOrientation = orientation;
519 // Change background visibility depending on orientation
520 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
522 if( mBackgroundRenderer )
524 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
525 mBackgroundVisible = false;
530 SetOpacityMode( mOpacityMode );
534 void IndicatorEcoreWl::Close()
536 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
538 if( mState == CONNECTED )
541 if( mObserver != NULL )
543 mObserver->IndicatorClosed( this );
547 Dali::Texture emptyTexture;
548 SetForegroundImage( emptyTexture );
551 void IndicatorEcoreWl::Flicked()
553 // if indicator is not showing, INDICATOR_FLICK_DONE is given
554 if( mVisible == Dali::Window::AUTO && !mIsShowing )
556 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
560 void IndicatorEcoreWl::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
564 Dali::Geometry geometry = CreateBackgroundGeometry();
567 if( mBackgroundRenderer )
569 if( mBackgroundRenderer.GetGeometry() != geometry )
571 mBackgroundRenderer.SetGeometry( geometry );
576 if( !mBackgroundShader )
578 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
581 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
584 if( !mBackgroundVisible )
586 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
587 mBackgroundVisible = true;
590 else if( mBackgroundRenderer )
592 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
593 mBackgroundVisible = false;
598 void IndicatorEcoreWl::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
600 if ( visibleMode != mVisible || forceUpdate )
602 // If we were previously hidden, then we should update the image data before we display the indicator
603 if ( mVisible == Dali::Window::INVISIBLE )
605 UpdateImageData( mCurrentSharedFile );
608 if ( visibleMode == Dali::Window::INVISIBLE )
610 if (mServerConnection)
612 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
617 mIndicatorActor.SetVisible( true );
619 if( mServerConnection )
621 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
625 mVisible = visibleMode;
628 if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
630 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
633 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
635 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
638 ShowIndicator( KEEP_SHOWING );
643 ShowIndicator( HIDE_NOW );
653 bool IndicatorEcoreWl::IsConnected()
655 return ( mState == CONNECTED );
658 bool IndicatorEcoreWl::SendMessage( int messageDomain, int messageId, const void *data, int size )
662 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
670 bool IndicatorEcoreWl::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
672 if( mServerConnection )
674 // Send touch event to indicator server when indicator is showing
675 if( CheckVisibleState() || mIsShowing )
677 switch( touchData.GetState(0) )
679 case Dali::PointState::DOWN:
681 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
682 IpcDataEvMouseDown ipcDown( touchData.GetTime() );
683 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
684 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
686 if( mVisible == Dali::Window::AUTO )
688 // Stop hiding indicator
689 ShowIndicator( KEEP_SHOWING );
694 case Dali::PointState::MOTION:
696 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
697 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
701 case Dali::PointState::UP:
702 case Dali::PointState::INTERRUPTED:
704 IpcDataEvMouseUp ipcUp( touchData.GetTime() );
705 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
707 if( mVisible == Dali::Window::AUTO )
710 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
715 case Dali::TouchPoint::Leave:
717 IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
718 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
719 IpcDataEvMouseUp ipcOut( touchData.GetTime() );
720 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
735 bool IndicatorEcoreWl::Connect()
737 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
739 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
741 bool connected = false;
743 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
744 if( mServerConnection )
746 connected = mServerConnection->IsConnected();
749 delete mServerConnection;
750 mServerConnection = NULL;
756 StartReconnectionTimer();
766 void IndicatorEcoreWl::StartReconnectionTimer()
768 if( ! mReconnectTimer )
770 mReconnectTimer = Dali::Timer::New(1000);
771 mConnection.DisconnectAll();
772 mReconnectTimer.TickSignal().Connect( mConnection, &IndicatorEcoreWl::OnReconnectTimer );
774 mReconnectTimer.Start();
777 bool IndicatorEcoreWl::OnReconnectTimer()
781 if( mState == DISCONNECTED )
792 void IndicatorEcoreWl::Disconnect()
794 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
796 mState = DISCONNECTED;
798 delete mServerConnection;
799 mServerConnection = NULL;
801 ClearSharedFileInfo();
804 void IndicatorEcoreWl::Resize( int width, int height )
815 if( mImageWidth != width || mImageHeight != height )
818 mImageHeight = height;
820 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
821 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
822 mEventActor.SetSize(mImageWidth, mImageHeight);
827 void IndicatorEcoreWl::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
829 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
831 // epcEvent->ref == w
832 // epcEvent->ref_to == h
833 // epcEvent->response == buffer num
834 // epcEvent->data = lockfile + nul byte
836 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
837 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
839 int n = epcEvent->response;
841 if( n >= 0 && n < SHARED_FILE_NUMBER )
843 mCurrentSharedFile = n;
845 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
846 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
848 mSharedFileInfo[n].mLockFileName.clear();
850 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
852 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
853 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
858 void IndicatorEcoreWl::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
860 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
862 // epcEvent->ref == shm id
863 // epcEvent->ref_to == shm num
864 // epcEvent->response == buffer num
865 // epcEvent->data = shm ref string + nul byte
867 if ( (epcEvent->data) &&
868 (epcEvent->size > 0) &&
869 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
871 int n = epcEvent->response;
873 if( n >= 0 && n < SHARED_FILE_NUMBER )
875 mCurrentSharedFile = n;
877 mSharedFileInfo[n].mSharedFileName.clear();
879 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
881 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
882 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
884 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
885 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
890 void IndicatorEcoreWl::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
892 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
894 // epcEvent->ref == alpha
895 // epcEvent->ref_to == sys
896 // epcEvent->response == buffer num
898 int n = epcEvent->response;
900 if( n >= 0 && n < SHARED_FILE_NUMBER )
902 mCurrentSharedFile = n;
904 delete mSharedFileInfo[n].mSharedFile;
905 mSharedFileInfo[n].mSharedFile = NULL;
907 delete mSharedFileInfo[n].mLock;
908 mSharedFileInfo[n].mLock = NULL;
910 std::stringstream sharedFileID;
911 std::stringstream sharedFileNumber;
913 sharedFileID << mSharedFileInfo[n].mSharedFileID;
914 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
916 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
918 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
920 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
921 if( mSharedFileInfo[n].mSharedFile != NULL )
923 mSharedFileInfo[n].mLock = new IndicatorEcoreWl::LockFile( mSharedFileInfo[n].mLockFileName );
924 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
926 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
937 void IndicatorEcoreWl::UpdateTopMargin()
939 int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
940 if (mTopMargin != newMargin)
942 mTopMargin = newMargin;
943 mAdaptor->IndicatorSizeChanged( mTopMargin );
947 void IndicatorEcoreWl::UpdateVisibility()
949 if( CheckVisibleState() )
951 // set default indicator type (enable the quick panel)
952 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
956 // set default indicator type (disable the quick panel)
957 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
962 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
965 SetVisible(mVisible, true);
968 void IndicatorEcoreWl::UpdateImageData( int bufferNumber )
970 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
972 if( mState == CONNECTED && mVisible )
974 // not sure we can skip it when mIsShowing is false
975 CopyToBuffer( bufferNumber );
979 bool IndicatorEcoreWl::CopyToBuffer( int bufferNumber )
981 bool success = false;
983 if( mSharedFileInfo[bufferNumber].mLock )
985 IndicatorEcoreWl::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
986 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
990 else if( scopedLock.IsLocked() )
992 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
993 size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
995 if( mIndicatorBuffer->UpdatePixels( src, size ) )
997 mAdaptor->RequestUpdateOnce();
1006 void IndicatorEcoreWl::CreateNewImage( int bufferNumber )
1008 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1009 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1010 bool success = false;
1012 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1014 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1017 SetForegroundImage( texture );
1024 DALI_LOG_WARNING("### Cannot create indicator image ###\n");
1028 Dali::Geometry IndicatorEcoreWl::CreateBackgroundGeometry()
1030 switch( mOpacityMode )
1032 case Dali::Window::TRANSLUCENT:
1033 if( !mTranslucentGeometry )
1035 // Construct 5 interval mesh
1049 struct BackgroundVertex
1055 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1056 BackgroundVertex vertices[ numVertices ];
1059 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1060 BackgroundVertex* currentVertex = vertices;
1061 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1063 currentVertex->mPosition = Vector2( -0.5f, d );
1064 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1067 currentVertex->mPosition = Vector2( 0.5f, d );
1068 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1073 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1074 unsigned short indices[ numIndices ];
1076 unsigned short* currentIndex = indices;
1077 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1079 *currentIndex++ = (2 * y);
1080 *currentIndex++ = (2 * y) + 3;
1081 *currentIndex++ = (2 * y) + 1;
1083 *currentIndex++ = (2 * y);
1084 *currentIndex++ = (2 * y) + 2;
1085 *currentIndex++ = (2 * y) + 3;
1088 Dali::Property::Map vertexFormat;
1089 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1090 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1091 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1092 vertexPropertyBuffer.SetData( vertices, numVertices );
1094 // Create the geometry object
1095 mTranslucentGeometry = Dali::Geometry::New();
1096 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1097 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1100 return mTranslucentGeometry;
1101 case Dali::Window::OPAQUE:
1103 if( !mSolidGeometry )
1106 struct BackgroundVertex
1112 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1113 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1116 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1118 Dali::Property::Map vertexFormat;
1119 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1120 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1121 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1122 vertexPropertyBuffer.SetData( vertices, 4 );
1125 // Create the geometry object
1126 mSolidGeometry = Dali::Geometry::New();
1127 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1128 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1131 return mSolidGeometry;
1132 case Dali::Window::TRANSPARENT:
1136 return Dali::Geometry();
1139 void IndicatorEcoreWl::SetForegroundImage( Dali::Texture texture )
1141 if( !mForegroundRenderer && texture )
1144 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1146 // Create renderer from geometry and material
1147 Dali::Geometry quad = CreateQuadGeometry();
1148 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1149 // Make sure the foreground stays in front of the background
1150 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1152 // Set blend function
1153 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1154 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1155 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1156 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1158 // Create a texture-set and add to renderer
1160 Dali::TextureSet textureSet = Dali::TextureSet::New();
1161 textureSet.SetTexture( 0u, texture );
1162 mForegroundRenderer.SetTextures( textureSet );
1164 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1166 else if( mForegroundRenderer )
1168 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1169 textureSet.SetTexture( 0u, texture );
1172 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1174 Resize( texture.GetWidth(), texture.GetHeight() );
1178 void IndicatorEcoreWl::OnIndicatorTypeChanged( Type indicatorType )
1180 if( mObserver != NULL )
1182 mObserver->IndicatorTypeChanged( indicatorType );
1186 void IndicatorEcoreWl::DataReceived( void* event )
1188 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1189 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1191 switch( epcEvent->minor )
1195 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1198 mAdaptor->RequestUpdateOnce();
1202 case OP_UPDATE_DONE:
1204 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1205 // epcEvent->response == display buffer #
1206 UpdateImageData( epcEvent->response );
1211 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1212 SetSharedImageInfo( epcEvent );
1217 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1218 SetLockFileInfo( epcEvent );
1223 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1224 LoadSharedImage( epcEvent );
1229 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1231 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1233 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1234 Resize( newSize->w, newSize->h );
1240 int msgDomain = epcEvent->ref;
1241 int msgId = epcEvent->ref_to;
1243 void *msgData = NULL;
1244 int msgDataSize = 0;
1245 msgData = epcEvent->data;
1246 msgDataSize = epcEvent->size;
1248 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1250 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1254 case MSG_ID_INDICATOR_TYPE:
1256 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1257 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1258 OnIndicatorTypeChanged( *indicatorType );
1262 case MSG_ID_INDICATOR_START_ANIMATION:
1264 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1266 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1268 DALI_LOG_ERROR("Message data is incorrect\n");
1272 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1274 if(!CheckVisibleState())
1276 ShowIndicator( animData->duration /* n sec */ );
1287 void IndicatorEcoreWl::ConnectionClosed()
1289 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1291 // Will get this callback if the server connection failed to start up.
1292 delete mServerConnection;
1293 mServerConnection = NULL;
1294 mState = DISCONNECTED;
1296 // Attempt to re-connect
1300 bool IndicatorEcoreWl::CheckVisibleState()
1302 if( mOrientation == Dali::Window::LANDSCAPE
1303 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1304 || (mVisible == Dali::Window::INVISIBLE)
1305 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1313 void IndicatorEcoreWl::ClearSharedFileInfo()
1315 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1317 delete mSharedFileInfo[i].mLock;
1318 mSharedFileInfo[i].mLock = NULL;
1320 delete mSharedFileInfo[i].mSharedFile;
1321 mSharedFileInfo[i].mSharedFile = NULL;
1323 mSharedFileInfo[i].mLockFileName.clear();
1324 mSharedFileInfo[i].mSharedFileName.clear();
1329 * duration can be this
1333 * KEEP_SHOWING = -1,
1337 void IndicatorEcoreWl::ShowIndicator(float duration)
1339 if( !mIndicatorAnimation )
1341 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1342 mIndicatorAnimation.FinishedSignal().Connect(this, &IndicatorEcoreWl::OnAnimationFinished);
1345 if(mIsShowing && !EqualsZero(duration))
1347 // If need to show during showing, do nothing.
1348 // In 2nd phase (below) will update timer
1350 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1352 // If need to hide during hiding or hidden already, do nothing
1356 mIndicatorAnimation.Clear();
1358 if( EqualsZero(duration) )
1360 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1364 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1368 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1372 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1375 mIndicatorAnimation.Play();
1376 mIsAnimationPlaying = true;
1383 mShowTimer = Dali::Timer::New(1000 * duration);
1384 mShowTimer.TickSignal().Connect(this, &IndicatorEcoreWl::OnShowTimer);
1386 mShowTimer.SetInterval(1000* duration);
1389 if( mVisible == Dali::Window::AUTO )
1391 // check the stage touch
1392 Dali::Stage::GetCurrent().TouchSignal().Connect( this, &IndicatorEcoreWl::OnStageTouch );
1397 if(mShowTimer && mShowTimer.IsRunning())
1402 if( mVisible == Dali::Window::AUTO )
1404 // check the stage touch
1405 Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &IndicatorEcoreWl::OnStageTouch );
1410 bool IndicatorEcoreWl::OnShowTimer()
1412 // after time up, hide indicator
1413 ShowIndicator( HIDE_NOW );
1418 void IndicatorEcoreWl::OnAnimationFinished(Dali::Animation& animation)
1420 mIsAnimationPlaying = false;
1421 // once animation is finished and indicator is hidden, take it off stage
1422 if( mObserver != NULL )
1424 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1428 void IndicatorEcoreWl::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1430 // Nothing to do, but we still want to consume pan
1433 void IndicatorEcoreWl::OnStageTouch(const Dali::TouchData& touchData)
1435 // when stage is touched while indicator is showing temporary, hide it
1436 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1438 switch( touchData.GetState(0) )
1440 case Dali::PointState::DOWN:
1442 // if touch point is inside the indicator, indicator is not hidden
1443 if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
1445 ShowIndicator( HIDE_NOW );
1462 #pragma GCC diagnostic pop