From: taeyoon Date: Wed, 30 Nov 2016 07:14:43 +0000 (+0900) Subject: [3.0] Add code to handle native indicator image X-Git-Tag: accepted/tizen/3.0/common/20161207.195829^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git;a=commitdiff_plain;h=2a82a722c32fe410b6228b7b9ba4c20046ff9c4c [3.0] Add code to handle native indicator image Change-Id: Id71160d8f5f863f13769dcb4d8438c28d7917840 --- diff --git a/adaptors/ecore/common/ecore-indicator-impl.h b/adaptors/ecore/common/ecore-indicator-impl.h index 1f0e693..b144fda 100644 --- a/adaptors/ecore/common/ecore-indicator-impl.h +++ b/adaptors/ecore/common/ecore-indicator-impl.h @@ -23,9 +23,12 @@ #include #include #include +#include +#include // INTERNAL INCLUDES #include +#include #include #include #include @@ -193,6 +196,12 @@ public: // Dali::Internal::Adaptor::IndicicatorInterface */ virtual bool SendMessage( int messageDomain, int messageId, const void *data, int size ); + /** + * Update native indicator image + * @param[in] source Native indicator image source + */ + void UpdateIndicatorImage( Dali::Any source ); + private: /** * Initialize the indicator actors @@ -211,6 +220,12 @@ private: void SetForegroundImage( Dali::Texture texture ); /** + * Set the texture to be rendered as indicator foreground + * @param[in] image The foreground image. + */ + void SetForegroundNativeImage( Dali::Image image ); + + /** * Touch event callback. * It should pass the valid touch event to indicator server * @@ -294,6 +309,12 @@ private: void UpdateTopMargin(); /** + * Setup native indicator image + * @param[in] epcEvent The event containing the image data information + */ + void SetupNativeIndicatorImage( Ecore_Ipc_Event_Server_Data *epcEvent ); + + /** * Update the visibility and position of the actors */ void UpdateVisibility(); @@ -355,6 +376,11 @@ private: */ void OnAnimationFinished( Dali::Animation& animation ); + /** + * Set up native indicator image + */ + void SetupNativeIndicatorImage(); + private: // Implementation of ServerConnection::Observer /** * @copydoc Dali::Internal::Adaptor::ServerConnection::Observer::DataReceived() @@ -409,6 +435,7 @@ private: IndicatorBufferPtr mIndicatorBuffer; ///< class which handles indicator rendering PixmapId mPixmap; ///< Pixmap including indicator content + Dali::NativeImageSourcePtr mNativeImageSource; Dali::Renderer mForegroundRenderer; ///< Renderer renders the indicator foreground Dali::Renderer mBackgroundRenderer; ///< Renderer renders the indicator background diff --git a/adaptors/ecore/common/file.list b/adaptors/ecore/common/file.list index e02a4ac..772e386 100644 --- a/adaptors/ecore/common/file.list +++ b/adaptors/ecore/common/file.list @@ -2,5 +2,7 @@ adaptor_ecore_common_internal_src_files = \ $(adaptor_ecore_common_dir)/ecore-virtual-keyboard.cpp \ - $(adaptor_ecore_common_dir)/ecore-indicator-impl.cpp \ $(adaptor_ecore_common_dir)/ecore-server-connection.cpp + +adaptor_ecore_common_internal_indicator_src_files = \ + $(adaptor_ecore_common_dir)/ecore-indicator-impl.cpp diff --git a/adaptors/tizen/ecore-indicator-impl-tizen.cpp b/adaptors/tizen/ecore-indicator-impl-tizen.cpp new file mode 100644 index 0000000..cdff69f --- /dev/null +++ b/adaptors/tizen/ecore-indicator-impl-tizen.cpp @@ -0,0 +1,1728 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "ecore-indicator-impl.h" + +// EXTERNAL INCLUDES +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include + +using Dali::Vector4; + +#if defined(DEBUG_ENABLED) +#define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN") +#endif + +namespace +{ + +const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds +const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds +const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels + +enum +{ + KEEP_SHOWING = -1, + HIDE_NOW = 0 +}; + +const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals +const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f }; + +#define MAKE_SHADER(A)#A + +const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER( + attribute mediump vec2 aPosition; + attribute mediump float aAlpha; + varying mediump float vAlpha; + uniform mediump mat4 uMvpMatrix; + uniform mediump vec3 uSize; + + void main() + { + mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 ); + vertexPosition = uMvpMatrix * vertexPosition; + + vAlpha = aAlpha; + gl_Position = vertexPosition; + } +); + +const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER( + uniform lowp vec4 uColor; + varying mediump float vAlpha; + + void main() + { + gl_FragColor = uColor; + gl_FragColor.a *= vAlpha; + } +); + +const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER( + attribute mediump vec2 aPosition;\n + varying mediump vec2 vTexCoord;\n + uniform mediump mat4 uMvpMatrix;\n + uniform mediump vec3 uSize;\n + uniform mediump vec4 sTextureRect;\n + \n + void main()\n + {\n + gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n + vTexCoord = aPosition + vec2(0.5);\n + }\n +); + +const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER( + varying mediump vec2 vTexCoord;\n + uniform sampler2D sTexture;\n + \n + void main()\n + {\n + gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color + }\n +); + +const char* FOREGROUND_TBM_FRAGMENT_SHADER = DALI_COMPOSE_SHADER( + varying mediump vec2 vTexCoord;\n + uniform samplerExternalOES sTexture;\n + \n + void main()\n + {\n + gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color + }\n +); + +Dali::Geometry CreateQuadGeometry() +{ + Dali::Property::Map quadVertexFormat; + quadVertexFormat["aPosition"] = Dali::Property::VECTOR2; + Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat ); + + const float halfQuadSize = .5f; + struct QuadVertex { Dali::Vector2 position; }; + QuadVertex quadVertexData[4] = { + { Dali::Vector2(-halfQuadSize, -halfQuadSize) }, + { Dali::Vector2(-halfQuadSize, halfQuadSize) }, + { Dali::Vector2( halfQuadSize, -halfQuadSize) }, + { Dali::Vector2( halfQuadSize, halfQuadSize) } }; + vertexData.SetData(quadVertexData, 4); + + Dali::Geometry quad = Dali::Geometry::New(); + quad.AddVertexBuffer( vertexData ); + quad.SetType( Dali::Geometry::TRIANGLE_STRIP ); + return quad; +} + +const float OPAQUE_THRESHOLD(0.99f); +const float TRANSPARENT_THRESHOLD(0.05f); + +// indicator service name +const char* INDICATOR_SERVICE_NAME("elm_indicator"); + +// Copied from ecore_evas_extn_engine.h + +#define NBUF 2 + +enum // opcodes +{ + OP_RESIZE, + OP_SHOW, + OP_HIDE, + OP_FOCUS, + OP_UNFOCUS, + OP_UPDATE, + OP_UPDATE_DONE, + OP_SHM_REF0, + OP_SHM_REF1, + OP_SHM_REF2, + OP_PROFILE_CHANGE_REQUEST, + OP_PROFILE_CHANGE_DONE, + OP_EV_MOUSE_IN, + OP_EV_MOUSE_OUT, + OP_EV_MOUSE_UP, + OP_EV_MOUSE_DOWN, + OP_EV_MOUSE_MOVE, + OP_EV_MOUSE_WHEEL, + OP_EV_MULTI_UP, + OP_EV_MULTI_DOWN, + OP_EV_MULTI_MOVE, + OP_EV_KEY_UP, + OP_EV_KEY_DOWN, + OP_EV_HOLD, + OP_MSG_PARENT, + OP_MSG, + OP_GL_REF, +}; + +// Copied from elm_conform.c + +const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 ); +const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 ); +const int MSG_ID_INDICATOR_ROTATION( 0x10003 ); +const int MSG_ID_INDICATOR_OPACITY( 0X1004 ); +const int MSG_ID_INDICATOR_TYPE( 0X1005 ); +const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 ); + +struct IpcDataUpdate +{ + int x, w, y, h; +}; + +struct IpcDataResize +{ + int w, h; +}; + +struct IpcIndicatorDataAnimation +{ + unsigned int xwin; + double duration; +}; + +struct IpcDataEvMouseUp +{ + int b; + Evas_Button_Flags flags; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; + + IpcDataEvMouseUp(unsigned long timestamp) + : b(1), + flags(EVAS_BUTTON_NONE), + mask(0), + timestamp(static_cast(timestamp)), + event_flags(EVAS_EVENT_FLAG_NONE) + { + } +}; + +struct IpcDataEvMouseDown +{ + int b; + Evas_Button_Flags flags; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; + + IpcDataEvMouseDown(unsigned long timestamp) + : b(1), + flags(EVAS_BUTTON_NONE), + mask(0), + timestamp(static_cast(timestamp)), + event_flags(EVAS_EVENT_FLAG_NONE) + { + } +}; + +struct IpcDataEvMouseMove +{ + int x, y; + Evas_Button_Flags flags; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; + + IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp) + : x(static_cast(touchPoint.local.x)), + y(static_cast(touchPoint.local.y)), + flags(EVAS_BUTTON_NONE), + mask(0), + timestamp(static_cast(timestamp)), + event_flags(EVAS_EVENT_FLAG_NONE) + { + } +}; + +struct IpcDataEvMouseOut +{ + unsigned int timestamp; + int mask; + Evas_Event_Flags event_flags; + + IpcDataEvMouseOut(unsigned long timestamp) + : timestamp(static_cast(timestamp)), + mask(0), + event_flags(EVAS_EVENT_FLAG_NONE) + { + } +}; + +static void UpdateIndicatorImage( void* data, struct tizen_remote_surface* remoteSurface, struct wl_buffer* buffer, uint32_t time ) +{ + Dali::Internal::Adaptor::Indicator* indicator = static_cast< Dali::Internal::Adaptor::Indicator* >( data ); + + if( indicator ) + { + tbm_surface_h tbmSurface = static_cast< tbm_surface_h >( wl_buffer_get_user_data( buffer ) ); + + indicator->UpdateIndicatorImage( tbmSurface ); + } +} + +static void MissingIndicatorImage( void* data, struct tizen_remote_surface* surface ) +{ +} + +static const struct tizen_remote_surface_listener remoteSurfaceCallback = +{ + UpdateIndicatorImage, + MissingIndicatorImage, +}; + +} // anonymous namespace + + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ +#if defined(DEBUG_ENABLED) +Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR"); +#endif + +// Impl to hide EFL implementation. + +struct Indicator::Impl +{ + enum // operation mode + { + INDICATOR_HIDE, + INDICATOR_STAY_WITH_DURATION + }; + + /** + * Constructor + */ + Impl(Indicator* indicator) + : mIndicator(indicator), + mEcoreEventHandler(NULL) + { +#if defined(DALI_PROFILE_MOBILE) + mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this); +#endif // WAYLAND && DALI_PROFILE_MOBILE + } + + /** + * Destructor + */ + ~Impl() + { + if ( mEcoreEventHandler ) + { + ecore_event_handler_del(mEcoreEventHandler); + } + } + + static void SetIndicatorVisibility( void* data, int operation ) + { + Indicator::Impl* indicatorImpl((Indicator::Impl*)data); + + if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL) + { + return; + } + if ( operation == INDICATOR_STAY_WITH_DURATION ) + { + // if indicator is not showing, INDICATOR_FLICK_DONE is given + if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO && + !indicatorImpl->mIndicator->mIsShowing ) + { + indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION ); + } + } + else if( operation == INDICATOR_HIDE ) + { + if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO && + indicatorImpl->mIndicator->mIsShowing ) + { + indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW ); + } + } + } +#if defined(DALI_PROFILE_MOBILE) + /** + * Called when the Ecore indicator event is received. + */ + static Eina_Bool EcoreEventIndicator( void* data, int type, void* event ) + { + SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION ); + return ECORE_CALLBACK_PASS_ON; + } +#endif // WAYLAND && DALI_PROFILE_MOBILE + + // Data + Indicator* mIndicator; + Ecore_Event_Handler* mEcoreEventHandler; +}; + +Indicator::LockFile::LockFile(const std::string filename) +: mFilename(filename), + mErrorThrown(false) +{ + mFileDescriptor = open(filename.c_str(), O_RDWR); + if( mFileDescriptor == -1 ) + { + mFileDescriptor = 0; + mErrorThrown = true; + DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() ); + } +} + +Indicator::LockFile::~LockFile() +{ + // Closing file descriptor also unlocks file. + close( mFileDescriptor ); +} + +bool Indicator::LockFile::Lock() +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + bool locked = false; + if( mFileDescriptor > 0 ) + { + if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block. + { + locked = true; + } + else + { + if( errno == EBADF ) + { + // file descriptor is no longer valid or not writable + mFileDescriptor = 0; + mErrorThrown = true; + DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() ); + } + } + } + + return locked; +} + +void Indicator::LockFile::Unlock() +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 ) + { + if( errno == EBADF ) + { + // file descriptor is no longer valid or not writable + mFileDescriptor = 0; + mErrorThrown = true; + DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() ); + } + } +} + +bool Indicator::LockFile::RetrieveAndClearErrorStatus() +{ + bool error = mErrorThrown; + mErrorThrown = false; + return error; +} + +Indicator::ScopedLock::ScopedLock(LockFile* lockFile) +: mLockFile(lockFile), + mLocked(false) +{ + if(mLockFile) + { + mLocked = mLockFile->Lock(); + } +} + +Indicator::ScopedLock::~ScopedLock() +{ + if( mLockFile ) + { + mLockFile->Unlock(); + } +} + +bool Indicator::ScopedLock::IsLocked() +{ + return mLocked; +} + +Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer ) +: mPixmap( 0 ), + mGestureDetected( false ), + mConnection( this ), + mOpacityMode( Dali::Window::OPAQUE ), + mState( DISCONNECTED ), + mAdaptor(adaptor), + mServerConnection( NULL ), + mObserver( observer ), + mOrientation( orientation ), + mImageWidth( 0 ), + mImageHeight( 0 ), + mVisible( Dali::Window::INVISIBLE ), + mIsShowing( true ), + mIsAnimationPlaying( false ), + mCurrentSharedFile( 0 ), + mSharedBufferType( BUFFER_TYPE_SHM ), + mImpl( NULL ), + mBackgroundVisible( false ) +{ + mIndicatorContentActor = Dali::Actor::New(); + mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER ); + mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + + // Indicator image handles the touch event including "leave" + mIndicatorContentActor.SetLeaveRequired( true ); + mIndicatorContentActor.TouchedSignal().Connect( this, &Indicator::OnTouched ); + mIndicatorContentActor.SetColor( Color::BLACK ); + + mIndicatorActor = Dali::Actor::New(); + mIndicatorActor.Add( mIndicatorContentActor ); + + // Event handler to find out flick down gesture + mEventActor = Dali::Actor::New(); + mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER ); + mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + mIndicatorActor.Add( mEventActor ); + + // Attach pan gesture to find flick down during hiding. + // It can prevent the problem that scrollview gets pan gesture even indicator area is touched, + // since it consumes the pan gesture in advance. + mPanDetector = Dali::PanGestureDetector::New(); + mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan ); + mPanDetector.Attach( mEventActor ); + + Open( orientation ); + + // register indicator to accessibility adaptor + Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get(); + if(accessibilityAdaptor) + { + AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this ); + } + // hide the indicator by default + mIndicatorActor.SetVisible( false ); + + // create impl to handle ecore event + mImpl = new Impl(this); +} + +Indicator::~Indicator() +{ + if(mImpl) + { + delete mImpl; + mImpl = NULL; + } + + if(mEventActor) + { + mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched ); + } + Disconnect(); +} + +void Indicator::SetAdaptor(Adaptor* adaptor) +{ + mAdaptor = adaptor; + mIndicatorBuffer->SetAdaptor( adaptor ); +} + +Dali::Actor Indicator::GetActor() +{ + return mIndicatorActor; +} + +void Indicator::Open( Dali::Window::WindowOrientation orientation ) +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + // Calls from Window should be set up to ensure we are in a + // disconnected state before opening a second time. + DALI_ASSERT_DEBUG( mState == DISCONNECTED ); + + mOrientation = orientation; + + Connect(); + + // Change background visibility depending on orientation + if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE ) + { + if( mBackgroundRenderer ) + { + mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer ); + mBackgroundVisible = false; + } + } + else + { + SetOpacityMode( mOpacityMode ); + } +} + +void Indicator::Close() +{ + DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) ); + + if( mState == CONNECTED ) + { + Disconnect(); + if( mObserver != NULL ) + { + mObserver->IndicatorClosed( this ); + } + } + + Dali::Texture emptyTexture; + SetForegroundImage( emptyTexture ); +} + +void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode ) +{ + mOpacityMode = mode; + + Dali::Geometry geometry = CreateBackgroundGeometry(); + if( geometry ) + { + if( mBackgroundRenderer ) + { + if( mBackgroundRenderer.GetGeometry() != geometry ) + { + mBackgroundRenderer.SetGeometry( geometry ); + } + } + else + { + if( !mBackgroundShader ) + { + mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT ); + } + + mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader ); + } + + if( !mBackgroundVisible ) + { + mIndicatorContentActor.AddRenderer( mBackgroundRenderer ); + mBackgroundVisible = true; + } + } + else if( mBackgroundRenderer ) + { + mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer ); + mBackgroundVisible = false; + } +} + +void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate ) +{ + if ( visibleMode != mVisible || forceUpdate ) + { + // If we were previously hidden, then we should update the image data before we display the indicator + if ( mVisible == Dali::Window::INVISIBLE ) + { + UpdateImageData( mCurrentSharedFile ); + } + + if ( visibleMode == Dali::Window::INVISIBLE ) + { + if (mServerConnection) + { + mServerConnection->SendEvent( OP_HIDE, NULL, 0 ); + } + } + else + { + mIndicatorActor.SetVisible( true ); + + if( mServerConnection ) + { + mServerConnection->SendEvent( OP_SHOW, NULL, 0 ); + } + } + + mVisible = visibleMode; + + if( mForegroundRenderer && + ( mForegroundRenderer.GetTextures().GetTexture( 0u ) || + Dali::TextureGetImage( mForegroundRenderer.GetTextures(), 0u ) ) + ) + { + if( CheckVisibleState() && mVisible == Dali::Window::AUTO ) + { + // hide indicator + ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ ); + } + else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE ) + { + // show indicator + ShowIndicator( KEEP_SHOWING ); + } + else + { + // hide indicator + ShowIndicator( HIDE_NOW ); + } + } + else + { + mIsShowing = false; + } + } +} + +bool Indicator::IsConnected() +{ + return ( mState == CONNECTED ); +} + +bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size ) +{ + if(IsConnected()) + { + return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size ); + } + else + { + return false; + } +} + +bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent) +{ + if( mServerConnection ) + { + const TouchPoint& touchPoint = touchEvent.GetPoint( 0 ); + + // Send touch event to indicator server when indicator is showing + if( CheckVisibleState() || mIsShowing ) + { + switch( touchPoint.state ) + { + case Dali::PointState::DOWN: + { + IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time ); + IpcDataEvMouseDown ipcDown( touchEvent.time ); + mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) ); + mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) ); + + if( mVisible == Dali::Window::AUTO ) + { + // Stop hiding indicator + ShowIndicator( KEEP_SHOWING ); + } + } + break; + + case Dali::PointState::MOTION: + { + IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time ); + mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) ); + } + break; + + case Dali::PointState::UP: + case Dali::PointState::INTERRUPTED: + { + IpcDataEvMouseUp ipcUp( touchEvent.time ); + mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) ); + + if( mVisible == Dali::Window::AUTO ) + { + // Hide indicator + ShowIndicator( 0.5f /* hide after 0.5 sec */ ); + } + } + break; + + case Dali::TouchPoint::Leave: + { + IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time ); + mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) ); + IpcDataEvMouseUp ipcOut( touchEvent.time ); + mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) ); + } + break; + + default: + break; + } + + return true; + } + } + + return false; +} + +bool Indicator::Connect() +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + DALI_ASSERT_DEBUG( mState == DISCONNECTED ); + + bool connected = false; + + mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this ); + if( mServerConnection ) + { + connected = mServerConnection->IsConnected(); + if( ! connected ) + { + delete mServerConnection; + mServerConnection = NULL; + } + } + + if( !connected ) + { + StartReconnectionTimer(); + } + else + { + mState = CONNECTED; + } + + return connected; +} + +void Indicator::StartReconnectionTimer() +{ + if( ! mReconnectTimer ) + { + mReconnectTimer = Dali::Timer::New(1000); + mConnection.DisconnectAll(); + mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer ); + } + mReconnectTimer.Start(); +} + +bool Indicator::OnReconnectTimer() +{ + bool retry = false; + + if( mState == DISCONNECTED ) + { + if( !Connect() ) + { + retry = true; + } + } + + return retry; +} + +void Indicator::Disconnect() +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + mState = DISCONNECTED; + + delete mServerConnection; + mServerConnection = NULL; + + ClearSharedFileInfo(); +} + +void Indicator::Resize( int width, int height ) +{ + if( width < 1 ) + { + width = 1; + } + if( height < 1 ) + { + height = 1; + } + + if( mImageWidth != width || mImageHeight != height ) + { + mImageWidth = width; + mImageHeight = height; + + mIndicatorContentActor.SetSize( mImageWidth, mImageHeight ); + mIndicatorActor.SetSize( mImageWidth, mImageHeight ); + mEventActor.SetSize(mImageWidth, mImageHeight); + } +} + +void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent ) +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + // epcEvent->ref == w + // epcEvent->ref_to == h + // epcEvent->response == buffer num + // epcEvent->data = lockfile + nul byte + + if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) && + (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) ) + { + int n = epcEvent->response; + + if( n >= 0 && n < SHARED_FILE_NUMBER ) + { + mCurrentSharedFile = n; + + mSharedFileInfo[n].mImageWidth = epcEvent->ref; + mSharedFileInfo[n].mImageHeight = epcEvent->ref_to; + + mSharedFileInfo[n].mLockFileName.clear(); + + mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data ); + + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n", + n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() ); + } + } +} + +void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent ) +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + // epcEvent->ref == shm id + // epcEvent->ref_to == shm num + // epcEvent->response == buffer num + // epcEvent->data = shm ref string + nul byte + + if ( (epcEvent->data) && + (epcEvent->size > 0) && + (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) ) + { + int n = epcEvent->response; + + if( n >= 0 && n < SHARED_FILE_NUMBER ) + { + mCurrentSharedFile = n; + + mSharedFileInfo[n].mSharedFileName.clear(); + + mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data ); + + mSharedFileInfo[n].mSharedFileID = epcEvent->ref; + mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to; + + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n", + n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber ); + } + } +} + +void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent ) +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + // epcEvent->ref == alpha + // epcEvent->ref_to == sys + // epcEvent->response == buffer num + + if ( mSharedBufferType != BUFFER_TYPE_SHM ) + { + return ; + } + + int n = epcEvent->response; + + if( n >= 0 && n < SHARED_FILE_NUMBER ) + { + mCurrentSharedFile = n; + + delete mSharedFileInfo[n].mSharedFile; + mSharedFileInfo[n].mSharedFile = NULL; + + delete mSharedFileInfo[n].mLock; + mSharedFileInfo[n].mLock = NULL; + + std::stringstream sharedFileID; + std::stringstream sharedFileNumber; + + sharedFileID << mSharedFileInfo[n].mSharedFileID; + sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber; + + std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str(); + + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() ); + + mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true ); + if( mSharedFileInfo[n].mSharedFile != NULL ) + { + mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName ); + if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() ) + { + DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() ); + } + + CreateNewImage( n ); + UpdateVisibility(); + } + } +} + +void Indicator::SetupNativeIndicatorImage( Ecore_Ipc_Event_Server_Data *epcEvent ) +{ + // Bind tizen remote surface + Eina_Inlist* globals; + Ecore_Wl_Global* global; + struct tizen_remote_surface_manager* remoteSurfaceManager = NULL; + struct tizen_remote_surface* remoteSurface = NULL; + struct wl_registry* registry; + struct wayland_tbm_client* tbmClient; + struct wl_tbm* wlTbm; + + if ( !remoteSurfaceManager ) + { + registry = ecore_wl_registry_get(); + globals = ecore_wl_globals_get(); + + if (!registry || !globals) + { + DALI_LOG_ERROR( "SetupNativeIndicatorImage registry or globals error\n" ); + return; + } + + EINA_INLIST_FOREACH(globals, global) + { + if (!strcmp(global->interface, "tizen_remote_surface_manager")) + { + remoteSurfaceManager = ( struct tizen_remote_surface_manager* )wl_registry_bind(registry, global->id, &tizen_remote_surface_manager_interface, 1); + } + } + } + if ( !remoteSurfaceManager ) + { + DALI_LOG_ERROR( "SetupNativeIndicatorImage bind error\n" ); + return; + } + + tbmClient = ( struct wayland_tbm_client* )wayland_tbm_client_init( ecore_wl_display_get() ); + if( !tbmClient ) + { + DALI_LOG_ERROR( "SetupNativeIndicatorImage client init error\n" ); + return; + } + + wlTbm = ( struct wl_tbm* )wayland_tbm_client_get_wl_tbm( tbmClient ); + if( !wlTbm ) + { + DALI_LOG_ERROR( "SetupNativeIndicatorImage wl tbm error\n" ); + return; + } + + uint32_t resourceId = epcEvent->ref; + remoteSurface = tizen_remote_surface_manager_create_surface( remoteSurfaceManager, resourceId, wlTbm ); + + if( !remoteSurface ) + { + DALI_LOG_ERROR( "SetupNativeIndicatorImage create surface error\n" ); + return; + } + + tizen_remote_surface_add_listener( remoteSurface, &remoteSurfaceCallback, this ); + tizen_remote_surface_redirect( remoteSurface ); + tizen_remote_surface_transfer_visibility( remoteSurface, TIZEN_REMOTE_SURFACE_VISIBILITY_TYPE_VISIBLE); +} + +void Indicator::UpdateIndicatorImage( Any source ) +{ + if( !mNativeImageSource ) + { + mNativeImageSource = Dali::NativeImageSource::New( source ); + Dali::NativeImage nativeImage = Dali::NativeImage::New( *mNativeImageSource ); + + SetForegroundNativeImage( nativeImage ); + mIndicatorContentActor.SetSize( mImageWidth, mImageHeight ); + mIndicatorActor.SetSize( mImageWidth, mImageHeight ); + mEventActor.SetSize( mImageWidth, mImageHeight ); + + UpdateVisibility(); + return; + } + + mNativeImageSource->SetSource( source ); + Dali::Stage::GetCurrent().KeepRendering( 0.0f ); +} + +void Indicator::UpdateVisibility() +{ + if( CheckVisibleState() ) + { + // set default indicator type (enable the quick panel) + OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); + } + else + { + // set default indicator type (disable the quick panel) + OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); + } + + if( !mIsShowing ) + { + mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f ); + } + + SetVisible(mVisible, true); +} + +void Indicator::UpdateImageData( int bufferNumber ) +{ + DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" ); + + if( mState == CONNECTED && mVisible ) + { + if(mPixmap == 0) + { + // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false + CopyToBuffer( bufferNumber ); + } + else + { + if(mIsShowing) + { + mAdaptor->RequestUpdateOnce(); + } + } + } +} + +bool Indicator::CopyToBuffer( int bufferNumber ) +{ + bool success = false; + + if( mSharedFileInfo[bufferNumber].mLock ) + { + Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock); + if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() ) + { + // Do nothing here. + } + else if( scopedLock.IsLocked() ) + { + unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress(); + size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4; + + if( mIndicatorBuffer->UpdatePixels( src, size ) ) + { + mAdaptor->RequestUpdateOnce(); + success = true; + } + } + } + + return success; +} + +void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent ) +{ +} + +void Indicator::CreateNewPixmapImage() +{ +} + +void Indicator::CreateNewImage( int bufferNumber ) +{ + DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight ); + mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 ); + bool success = false; + + if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer + { + Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() ); + if( texture ) + { + SetForegroundImage( texture ); + success = true; + } + } + + if( !success ) + { + DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n"); + Disconnect(); + if( mObserver != NULL ) + { + mObserver->IndicatorClosed( this ); + } + // Don't do connection in this callback - strange things happen! + StartReconnectionTimer(); + } +} + +Dali::Geometry Indicator::CreateBackgroundGeometry() +{ + switch( mOpacityMode ) + { + case Dali::Window::TRANSLUCENT: + if( !mTranslucentGeometry ) + { + // Construct 5 interval mesh + // 0 +---+ 1 + // | \ | + // 2 +---+ 3 + // | \ | + // 4 +---+ 5 + // | \ | + // 6 +---+ 7 + // | \ | + // 8 +---+ 9 + // | \ | + // 10 +---+ 11 + + // Create vertices + struct BackgroundVertex + { + Vector2 mPosition; + float mAlpha; + }; + + unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 ); + BackgroundVertex vertices[ numVertices ]; + + float d = -0.5f; + float delta = 1.0f / NUM_GRADIENT_INTERVALS; + BackgroundVertex* currentVertex = vertices; + for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta ) + { + currentVertex->mPosition = Vector2( -0.5f, d ); + currentVertex->mAlpha = GRADIENT_ALPHA[ y ]; + currentVertex++; + + currentVertex->mPosition = Vector2( 0.5f, d ); + currentVertex->mAlpha = GRADIENT_ALPHA[ y ]; + currentVertex++; + } + + // Create indices + unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS; + unsigned short indices[ numIndices ]; + + unsigned short* currentIndex = indices; + for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y ) + { + *currentIndex++ = (2 * y); + *currentIndex++ = (2 * y) + 3; + *currentIndex++ = (2 * y) + 1; + + *currentIndex++ = (2 * y); + *currentIndex++ = (2 * y) + 2; + *currentIndex++ = (2 * y) + 3; + } + + Dali::Property::Map vertexFormat; + vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2; + vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT; + Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat ); + vertexPropertyBuffer.SetData( vertices, numVertices ); + + // Create the geometry object + mTranslucentGeometry = Dali::Geometry::New(); + mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer ); + mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices ); + } + + return mTranslucentGeometry; + case Dali::Window::OPAQUE: + + if( !mSolidGeometry ) + { + // Create vertices + struct BackgroundVertex + { + Vector2 mPosition; + float mAlpha; + }; + + BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f }, + { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } }; + + // Create indices + unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 }; + + Dali::Property::Map vertexFormat; + vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2; + vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT; + Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat ); + vertexPropertyBuffer.SetData( vertices, 4 ); + + + // Create the geometry object + mSolidGeometry = Dali::Geometry::New(); + mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer ); + mSolidGeometry.SetIndexBuffer( &indices[0], 6 ); + } + + return mSolidGeometry; + case Dali::Window::TRANSPARENT: + break; + } + + return Dali::Geometry(); +} + +void Indicator::SetForegroundImage( Dali::Texture texture ) +{ + if( !mForegroundRenderer && texture ) + { + // Create Shader + Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER ); + + // Create renderer from geometry and material + Dali::Geometry quad = CreateQuadGeometry(); + mForegroundRenderer = Dali::Renderer::New( quad, shader ); + // Make sure the foreground stays in front of the background + mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f ); + + // Set blend function + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE ); + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA ); + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE ); + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE ); + + // Create a texture-set and add to renderer + + Dali::TextureSet textureSet = Dali::TextureSet::New(); + textureSet.SetTexture( 0u, texture ); + mForegroundRenderer.SetTextures( textureSet ); + + mIndicatorContentActor.AddRenderer( mForegroundRenderer ); + } + else if( mForegroundRenderer ) + { + Dali::TextureSet textureSet = mForegroundRenderer.GetTextures(); + textureSet.SetTexture( 0u, texture ); + } + + if( mImageWidth == 0 && mImageHeight == 0 && texture) + { + Resize( texture.GetWidth(), texture.GetHeight() ); + } +} + +void Indicator::SetForegroundNativeImage( Dali::Image image ) +{ + if( !mForegroundRenderer && image ) + { + + std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n"; + fragmentShader += "\n"; + fragmentShader += FOREGROUND_TBM_FRAGMENT_SHADER; + + // Create Shader + Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, fragmentShader ); + + // Create renderer from geometry and material + Dali::Geometry quad = CreateQuadGeometry(); + mForegroundRenderer = Dali::Renderer::New( quad, shader ); + // Make sure the foreground stays in front of the background + mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f ); + + // Set blend function + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE ); + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA ); + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE ); + mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE ); + + // Create a texture-set and add to renderer + + Dali::TextureSet textureSet = Dali::TextureSet::New(); + Dali::TextureSetImage( textureSet, 0u, image ); + + mForegroundRenderer.SetTextures( textureSet ); + + mIndicatorContentActor.AddRenderer( mForegroundRenderer ); + } + else if( mForegroundRenderer ) + { + Dali::TextureSet textureSet = mForegroundRenderer.GetTextures(); + Dali::TextureSetImage( textureSet, 0u, image ); + } + + if( mImageWidth == 0 && mImageHeight == 0 && image ) + { + Resize( image.GetWidth(), image.GetHeight() ); + } +} + +void Indicator::OnIndicatorTypeChanged( Type indicatorType ) +{ + if( mObserver != NULL ) + { + mObserver->IndicatorTypeChanged( indicatorType ); + } +} + +void Indicator::DataReceived( void* event ) +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + Ecore_Ipc_Event_Server_Data *epcEvent = static_cast( event ); + + switch( epcEvent->minor ) + { + case OP_UPDATE: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" ); + if( mIsShowing ) + { + mAdaptor->RequestUpdateOnce(); + } + break; + } + case OP_UPDATE_DONE: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response ); + // epcEvent->response == display buffer # + UpdateImageData( epcEvent->response ); + break; + } + case OP_SHM_REF0: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" ); + SetSharedImageInfo( epcEvent ); + break; + } + case OP_SHM_REF1: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" ); + SetLockFileInfo( epcEvent ); + break; + } + case OP_SHM_REF2: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" ); + LoadSharedImage( epcEvent ); + break; + } + case OP_GL_REF: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_GL_REF\n" ); + SetupNativeIndicatorImage( epcEvent ); + break; + } + case OP_RESIZE: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" ); + + if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) ) + { + IpcDataResize *newSize = static_cast( epcEvent->data ); + Resize( newSize->w, newSize->h ); + } + break; + } + case OP_MSG_PARENT: + { + int msgDomain = epcEvent->ref; + int msgId = epcEvent->ref_to; + + void *msgData = NULL; + int msgDataSize = 0; + msgData = epcEvent->data; + msgDataSize = epcEvent->size; + + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain ); + + if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR ) + { + switch( msgId ) + { + case MSG_ID_INDICATOR_TYPE: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" ); + Type* indicatorType = static_cast( epcEvent->data ); + OnIndicatorTypeChanged( *indicatorType ); + break; + } + + case MSG_ID_INDICATOR_START_ANIMATION: + { + DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" ); + + if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation)) + { + DALI_LOG_ERROR("Message data is incorrect\n"); + break; + } + + IpcIndicatorDataAnimation *animData = static_cast(msgData); + + if(!CheckVisibleState()) + { + ShowIndicator( animData->duration /* n sec */ ); + } + break; + } + } + } + break; + } + } +} + +void Indicator::ConnectionClosed() +{ + DALI_LOG_TRACE_METHOD( gIndicatorLogFilter ); + + // Will get this callback if the server connection failed to start up. + delete mServerConnection; + mServerConnection = NULL; + mState = DISCONNECTED; + + // Attempt to re-connect + Connect(); +} + +bool Indicator::CheckVisibleState() +{ + if( mOrientation == Dali::Window::LANDSCAPE + || mOrientation == Dali::Window::LANDSCAPE_INVERSE + || (mVisible == Dali::Window::INVISIBLE) + || (mVisible == Dali::Window::AUTO && !mIsShowing) ) + { + return false; + } + + return true; +} + +void Indicator::ClearSharedFileInfo() +{ + for( int i = 0; i < SHARED_FILE_NUMBER; i++ ) + { + delete mSharedFileInfo[i].mLock; + mSharedFileInfo[i].mLock = NULL; + + delete mSharedFileInfo[i].mSharedFile; + mSharedFileInfo[i].mSharedFile = NULL; + + mSharedFileInfo[i].mLockFileName.clear(); + mSharedFileInfo[i].mSharedFileName.clear(); + } +} + +/** + * duration can be this + * + * enum + * { + * KEEP_SHOWING = -1, + * HIDE_NOW = 0 + * }; + */ +void Indicator::ShowIndicator(float duration) +{ + if( !mIndicatorAnimation ) + { + mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION); + mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished); + } + + if(mIsShowing && !EqualsZero(duration)) + { + // If need to show during showing, do nothing. + // In 2nd phase (below) will update timer + } + else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration)) + { + // If need to hide during hiding or hidden already, do nothing + } + else + { + mIndicatorAnimation.Clear(); + + if( EqualsZero(duration) ) + { + mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT ); + + mIsShowing = false; + + OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable + } + else + { + mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT ); + + mIsShowing = true; + + OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable + } + + mIndicatorAnimation.Play(); + mIsAnimationPlaying = true; + } + + if(duration > 0) + { + if(!mShowTimer) + { + mShowTimer = Dali::Timer::New(1000 * duration); + mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer); + } + mShowTimer.SetInterval(1000* duration); + mShowTimer.Start(); + + if( mVisible == Dali::Window::AUTO ) + { + // check the stage touch + Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched ); + } + } + else + { + if(mShowTimer && mShowTimer.IsRunning()) + { + mShowTimer.Stop(); + } + + if( mVisible == Dali::Window::AUTO ) + { + // check the stage touch + Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched ); + } + } +} + +bool Indicator::OnShowTimer() +{ + // after time up, hide indicator + ShowIndicator( HIDE_NOW ); + + return false; +} + +void Indicator::OnAnimationFinished(Dali::Animation& animation) +{ + mIsAnimationPlaying = false; + // once animation is finished and indicator is hidden, take it off stage + if( mObserver != NULL ) + { + mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing? + } +} + +void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture ) +{ + return ; + + if( mServerConnection ) + { + switch( gesture.state ) + { + case Gesture::Started: + { + mGestureDetected = false; + + // The gesture position is the current position after it has moved by the displacement. + // We want to reference the original position. + mGestureDeltaY = gesture.position.y - gesture.displacement.y; + } + + // No break, Fall through + case Gesture::Continuing: + { + if( mVisible == Dali::Window::AUTO && !mIsShowing ) + { + // Only take one touch point + if( gesture.numberOfTouches == 1 && mGestureDetected == false ) + { + mGestureDeltaY += gesture.displacement.y; + + if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE ) + { + ShowIndicator( AUTO_INDICATOR_STAY_DURATION ); + mGestureDetected = true; + } + } + } + + break; + } + + case Gesture::Finished: + case Gesture::Cancelled: + { + // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up) + if( mVisible == Dali::Window::AUTO && mIsShowing ) + { + ShowIndicator( AUTO_INDICATOR_STAY_DURATION ); + } + break; + } + + + default: + break; + } + } +} + +void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent) +{ + const TouchPoint& touchPoint = touchEvent.GetPoint( 0 ); + + // when stage is touched while indicator is showing temporary, hide it + if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) ) + { + switch( touchPoint.state ) + { + case Dali::PointState::DOWN: + { + // if touch point is inside the indicator, indicator is not hidden + if( mImageHeight < int(touchPoint.screen.y) ) + { + ShowIndicator( HIDE_NOW ); + } + break; + } + + default: + break; + } + } +} + +} // Adaptor +} // Internal +} // Dali diff --git a/adaptors/tizen/file.list b/adaptors/tizen/file.list index 247a9a3..79f2dc9 100644 --- a/adaptors/tizen/file.list +++ b/adaptors/tizen/file.list @@ -22,3 +22,6 @@ adaptor_tizen_internal_native_image_src_files = \ public_api_adaptor_tizen_header_files = \ $(adaptor_tizen_dir)/key-grab.h + +adaptor_tizen_internal_indicator_src_files = \ + $(adaptor_tizen_dir)/ecore-indicator-impl-tizen.cpp diff --git a/build/tizen/adaptor/Makefile.am b/build/tizen/adaptor/Makefile.am index 1d7f936..4bf8c97 100644 --- a/build/tizen/adaptor/Makefile.am +++ b/build/tizen/adaptor/Makefile.am @@ -122,6 +122,13 @@ include ../../../doc/file.list if USE_EFL adaptor_internal_src_files = $(adaptor_tizen_framework_efl_src_files) \ $(adaptor_ecore_common_internal_src_files) + +if WAYLAND +adaptor_internal_src_files += $(adaptor_tizen_internal_indicator_src_files) +else +adaptor_internal_src_files += $(adaptor_ecore_common_internal_indicator_src_files) +endif + else adaptor_internal_src_files = $(adaptor_tizen_framework_libuv_src_files) endif diff --git a/build/tizen/adaptor/configure.ac b/build/tizen/adaptor/configure.ac index e9f3994..529179f 100644 --- a/build/tizen/adaptor/configure.ac +++ b/build/tizen/adaptor/configure.ac @@ -270,7 +270,7 @@ fi # Using EFL api's for WAYLAND AND X11 to run on ecore mainloop if test "x$enable_efl" = "xyes"; then if test "x$enable_wayland" = "xyes"; then -PKG_CHECK_MODULES(WAYLAND, [ecore-wayland egl wayland-egl wayland-client >= 1.2.0 xkbcommon libtbm], +PKG_CHECK_MODULES(WAYLAND, [ecore-wayland egl wayland-egl wayland-client >= 1.2.0 xkbcommon libtbm wayland-tbm-client tizen-remote-surface-client], [DALI_USE_ECORE_WAYLAND=1], [DALI_USE_ECORE_WAYLAND=0]) diff --git a/packaging/dali-adaptor.spec b/packaging/dali-adaptor.spec index 4c12438..154d565 100644 --- a/packaging/dali-adaptor.spec +++ b/packaging/dali-adaptor.spec @@ -134,6 +134,8 @@ BuildRequires: libxkbcommon-devel # dali-adaptor uses ecore mainloop BuildRequires: pkgconfig(ecore-wayland) +BuildRequires: pkgconfig(wayland-tbm-client) +BuildRequires: pkgconfig(tizen-extension-client) # dali-adaptor needs tbm_surface in tizen 3.0 wayland BuildRequires: pkgconfig(libtbm)