Merge branch 'devel/master(1.2.18)' into tizen
[platform/core/uifw/dali-adaptor.git] / adaptors / ecore / common / ecore-indicator-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "ecore-indicator-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <Ecore.h>
23 #include <Evas.h>
24 #ifdef WAYLAND
25 #include <Ecore_Wayland.h>
26 #else
27 #include <Ecore_X.h>
28 #endif
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <iomanip>
36 #include <fstream>
37
38 #include <dali/public-api/images/native-image.h>
39 #include <dali/public-api/events/touch-event.h>
40 #include <dali/public-api/events/touch-point.h>
41 #include <dali/public-api/common/stage.h>
42 #include <dali/public-api/images/buffer-image.h>
43 #include <dali/public-api/images/pixel.h>
44
45 #include <dali/integration-api/debug.h>
46
47 // INTERNAL INCLUDES
48 #include <adaptor-impl.h>
49 #include <accessibility-adaptor-impl.h>
50 #include <native-image-source.h>
51
52 using Dali::Vector4;
53
54 #if defined(DEBUG_ENABLED)
55 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
56 #endif
57
58 namespace
59 {
60
61 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
62 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
63 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
64
65 enum
66 {
67   KEEP_SHOWING = -1,
68   HIDE_NOW = 0
69 };
70
71 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
72 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
73
74 #define MAKE_SHADER(A)#A
75
76 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
77   attribute mediump vec2 aPosition;
78   attribute mediump float aAlpha;
79   varying mediump float vAlpha;
80   uniform mediump mat4 uMvpMatrix;
81   uniform mediump vec3 uSize;
82
83   void main()
84   {
85     mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
86     vertexPosition = uMvpMatrix * vertexPosition;
87
88     vAlpha = aAlpha;
89     gl_Position = vertexPosition;
90   }
91 );
92
93 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
94   uniform lowp vec4 uColor;
95   varying mediump float vAlpha;
96
97   void main()
98   {
99     gl_FragColor = uColor;
100     gl_FragColor.a *= vAlpha;
101   }
102 );
103
104 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
105   attribute mediump vec2 aPosition;\n
106   varying mediump vec2 vTexCoord;\n
107   uniform mediump mat4 uMvpMatrix;\n
108   uniform mediump vec3 uSize;\n
109   uniform mediump vec4 sTextureRect;\n
110   \n
111   void main()\n
112   {\n
113     gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
114     vTexCoord = aPosition + vec2(0.5);\n
115   }\n
116 );
117
118 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
119   varying mediump vec2 vTexCoord;\n
120   uniform sampler2D sTexture;\n
121   \n
122   void main()\n
123   {\n
124     gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
125   }\n
126 );
127
128 Dali::Geometry CreateQuadGeometry()
129 {
130   Dali::Property::Map quadVertexFormat;
131   quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
132   Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
133
134   const float halfQuadSize = .5f;
135   struct QuadVertex { Dali::Vector2 position; };
136   QuadVertex quadVertexData[4] = {
137       { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
138       { Dali::Vector2(-halfQuadSize, halfQuadSize) },
139       { Dali::Vector2( halfQuadSize, -halfQuadSize) },
140       { Dali::Vector2( halfQuadSize, halfQuadSize) } };
141   vertexData.SetData(quadVertexData, 4);
142
143   Dali::Geometry quad = Dali::Geometry::New();
144   quad.AddVertexBuffer( vertexData );
145   quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
146   return quad;
147 }
148
149 const float OPAQUE_THRESHOLD(0.99f);
150 const float TRANSPARENT_THRESHOLD(0.05f);
151
152 // indicator service name
153 const char* INDICATOR_SERVICE_NAME("elm_indicator");
154
155 // Copied from ecore_evas_extn_engine.h
156
157 #define NBUF 2
158
159 enum // opcodes
160 {
161    OP_RESIZE,
162    OP_SHOW,
163    OP_HIDE,
164    OP_FOCUS,
165    OP_UNFOCUS,
166    OP_UPDATE,
167    OP_UPDATE_DONE,
168    OP_SHM_REF0,
169    OP_SHM_REF1,
170    OP_SHM_REF2,
171    OP_PROFILE_CHANGE_REQUEST,
172    OP_PROFILE_CHANGE_DONE,
173    OP_EV_MOUSE_IN,
174    OP_EV_MOUSE_OUT,
175    OP_EV_MOUSE_UP,
176    OP_EV_MOUSE_DOWN,
177    OP_EV_MOUSE_MOVE,
178    OP_EV_MOUSE_WHEEL,
179    OP_EV_MULTI_UP,
180    OP_EV_MULTI_DOWN,
181    OP_EV_MULTI_MOVE,
182    OP_EV_KEY_UP,
183    OP_EV_KEY_DOWN,
184    OP_EV_HOLD,
185    OP_MSG_PARENT,
186    OP_MSG,
187    OP_PIXMAP_REF,
188 };
189
190 // Copied from elm_conform.c
191
192 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
193 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
194 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
195 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
196 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
197 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
198
199 struct IpcDataUpdate
200 {
201    int x, w, y, h;
202 };
203
204 struct IpcDataResize
205 {
206   int w, h;
207 };
208
209 struct IpcIndicatorDataAnimation
210 {
211   unsigned int xwin;
212   double       duration;
213 };
214
215 struct IpcDataEvMouseUp
216 {
217   int               b;
218   Evas_Button_Flags flags;
219   int               mask;
220   unsigned int      timestamp;
221   Evas_Event_Flags  event_flags;
222
223   IpcDataEvMouseUp(unsigned long timestamp)
224   : b(1),
225     flags(EVAS_BUTTON_NONE),
226     mask(0),
227     timestamp(static_cast<unsigned int>(timestamp)),
228     event_flags(EVAS_EVENT_FLAG_NONE)
229   {
230   }
231 };
232
233 struct IpcDataEvMouseDown
234 {
235   int                b;
236   Evas_Button_Flags  flags;
237   int                mask;
238   unsigned int       timestamp;
239   Evas_Event_Flags   event_flags;
240
241   IpcDataEvMouseDown(unsigned long timestamp)
242   : b(1),
243     flags(EVAS_BUTTON_NONE),
244     mask(0),
245     timestamp(static_cast<unsigned int>(timestamp)),
246     event_flags(EVAS_EVENT_FLAG_NONE)
247   {
248   }
249 };
250
251 struct IpcDataEvMouseMove
252 {
253   int                x, y;
254   Evas_Button_Flags  flags;
255   int                mask;
256   unsigned int       timestamp;
257   Evas_Event_Flags   event_flags;
258
259   IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
260   : x(static_cast<Evas_Coord>(touchPoint.local.x)),
261     y(static_cast<Evas_Coord>(touchPoint.local.y)),
262     flags(EVAS_BUTTON_NONE),
263     mask(0),
264     timestamp(static_cast<unsigned int>(timestamp)),
265     event_flags(EVAS_EVENT_FLAG_NONE)
266   {
267   }
268 };
269
270 struct IpcDataEvMouseOut
271 {
272   unsigned int     timestamp;
273   int              mask;
274   Evas_Event_Flags event_flags;
275
276   IpcDataEvMouseOut(unsigned long timestamp)
277   : timestamp(static_cast<unsigned int>(timestamp)),
278     mask(0),
279     event_flags(EVAS_EVENT_FLAG_NONE)
280   {
281   }
282 };
283
284 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
285
286 void SaveIndicatorImage( Dali::NativeImageSourcePtr nativeImageSource )
287 {
288   // Save image data to disk in BMP form.
289   static int gFilenameCounter = 0;
290   static const char bmpHeader[] = {
291       0x42, 0x4d, 0x0a, 0xcb, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x7c, 0x00,
292       0x00, 0x00,
293       0xe0, 0x01, 0x00, 0x00, // Width  (480)
294       0x1b, 0x00, 0x00, 0x00, // Height ( 27)
295       0x01, 0x00, 0x20, 0x00, 0x03, 0x00,
296       0x00, 0x00, 0x80, 0xca, 0x00, 0x00, 0x13, 0x0b,  0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
297       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
298       0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x42, 0x47,  0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
302       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00
303     };
304
305   // This is a BMP header with width & height hard-coded in.
306   // The data was first determined by dumping the raw data and inspecting in GIMP, before creating this header data.
307   std::vector<unsigned char> buffer;
308   unsigned int w = 0;
309   unsigned int h = 0;
310   Dali::Pixel::Format pixelFormat;
311   if( nativeImageSource->GetPixels( buffer, w, h, pixelFormat ) )
312   {
313     int imageSize = w * h * 4;
314     std::stringstream fileName;
315     // Give each file an incremental filename.
316     fileName << "/opt/usr/media/Images/out-" << std::setfill( '0' ) << std::setw( 5 ) << gFilenameCounter << ".bmp";
317
318     std::ofstream outfile( fileName.str().c_str(), std::ofstream::binary );
319     if( outfile.is_open() )
320     {
321       DALI_LOG_WARNING( "Saving Indicator Image w:%d, h:%d, %s\n", w, h, fileName.str().c_str() );
322
323       outfile.write( bmpHeader, sizeof( bmpHeader ) / sizeof( bmpHeader[0] ) ); // Size of the BMP header.
324       outfile.write( (const char*)buffer.data(), imageSize );
325       outfile.close();
326       gFilenameCounter++;
327     }
328     else
329     {
330       DALI_LOG_ERROR( "COULD NOT OPEN FOR SAVING: %s\n", fileName.str().c_str() );
331     }
332   }
333 }
334
335 #endif
336
337 } // anonymous namespace
338
339
340 namespace Dali
341 {
342 namespace Internal
343 {
344 namespace Adaptor
345 {
346 #if defined(DEBUG_ENABLED)
347 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
348 #endif
349
350 // Impl to hide EFL implementation.
351
352 struct Indicator::Impl
353 {
354   enum // operation mode
355   {
356     INDICATOR_HIDE,
357     INDICATOR_STAY_WITH_DURATION
358   };
359
360   /**
361    * Constructor
362    */
363   Impl(Indicator* indicator)
364   : mIndicator(indicator),
365     mEcoreEventHandler(NULL)
366   {
367 #if defined(DALI_PROFILE_MOBILE)
368 #if defined(WAYLAND)
369     mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK,  EcoreEventIndicator, this);
370 #else
371     mEcoreEventHandler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,  EcoreEventClientMessage, this);
372 #endif
373 #endif // WAYLAND && DALI_PROFILE_MOBILE
374   }
375
376   /**
377    * Destructor
378    */
379   ~Impl()
380   {
381     if ( mEcoreEventHandler )
382     {
383       ecore_event_handler_del(mEcoreEventHandler);
384     }
385   }
386
387   static void SetIndicatorVisibility( void* data, int operation )
388   {
389     Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
390
391     if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
392     {
393       return;
394     }
395     if ( operation == INDICATOR_STAY_WITH_DURATION )
396     {
397       // if indicator is not showing, INDICATOR_FLICK_DONE is given
398       if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
399           !indicatorImpl->mIndicator->mIsShowing )
400       {
401         indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
402       }
403     }
404     else if( operation == INDICATOR_HIDE )
405     {
406       if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
407           indicatorImpl->mIndicator->mIsShowing )
408       {
409         indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
410       }
411     }
412   }
413 #if defined(DALI_PROFILE_MOBILE)
414 #if defined(WAYLAND)
415   /**
416    * Called when the Ecore indicator event is received.
417    */
418   static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
419   {
420     SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
421     return ECORE_CALLBACK_PASS_ON;
422   }
423 #else
424   /**
425    * Called when the client messages (i.e. quick panel state) are received.
426    */
427   static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
428   {
429     Ecore_X_Event_Client_Message* clientMessageEvent((Ecore_X_Event_Client_Message*)event);
430
431     if ( clientMessageEvent != NULL )
432     {
433       if (clientMessageEvent->message_type == ECORE_X_ATOM_E_INDICATOR_FLICK_DONE)
434       {
435         SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
436       }
437       else if ( clientMessageEvent->message_type == ECORE_X_ATOM_E_MOVE_QUICKPANEL_STATE )
438       {
439         SetIndicatorVisibility( data, INDICATOR_HIDE );
440       }
441     }
442     return ECORE_CALLBACK_PASS_ON;
443   }
444 #endif
445 #endif // WAYLAND && DALI_PROFILE_MOBILE
446
447   // Data
448   Indicator*           mIndicator;
449   Ecore_Event_Handler* mEcoreEventHandler;
450 };
451
452 Indicator::LockFile::LockFile(const std::string filename)
453 : mFilename(filename),
454   mErrorThrown(false)
455 {
456   mFileDescriptor = open(filename.c_str(), O_RDWR);
457   if( mFileDescriptor == -1 )
458   {
459     mFileDescriptor = 0;
460     mErrorThrown = true;
461     DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
462   }
463 }
464
465 Indicator::LockFile::~LockFile()
466 {
467   // Closing file descriptor also unlocks file.
468   close( mFileDescriptor );
469 }
470
471 bool Indicator::LockFile::Lock()
472 {
473   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
474
475   bool locked = false;
476   if( mFileDescriptor > 0 )
477   {
478     if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
479     {
480       locked = true;
481     }
482     else
483     {
484       if( errno == EBADF )
485       {
486         // file descriptor is no longer valid or not writable
487         mFileDescriptor = 0;
488         mErrorThrown = true;
489         DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
490       }
491     }
492   }
493
494   return locked;
495 }
496
497 void Indicator::LockFile::Unlock()
498 {
499   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
500   if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
501   {
502     if( errno == EBADF )
503     {
504       // file descriptor is no longer valid or not writable
505       mFileDescriptor = 0;
506       mErrorThrown = true;
507       DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
508     }
509   }
510 }
511
512 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
513 {
514   bool error = mErrorThrown;
515   mErrorThrown = false;
516   return error;
517 }
518
519 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
520 : mLockFile(lockFile),
521   mLocked(false)
522 {
523   if(mLockFile)
524   {
525     mLocked = mLockFile->Lock();
526   }
527 }
528
529 Indicator::ScopedLock::~ScopedLock()
530 {
531   if( mLockFile )
532   {
533     mLockFile->Unlock();
534   }
535 }
536
537 bool Indicator::ScopedLock::IsLocked()
538 {
539   return mLocked;
540 }
541
542 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
543 : mPixmap( 0 ),
544   mGestureDeltaY( 0.0f ),
545   mGestureDetected( false ),
546   mConnection( this ),
547   mOpacityMode( Dali::Window::OPAQUE ),
548   mState( DISCONNECTED ),
549   mAdaptor(adaptor),
550   mServerConnection( NULL ),
551   mObserver( observer ),
552   mOrientation( orientation ),
553   mImageWidth( 0 ),
554   mImageHeight( 0 ),
555   mVisible( Dali::Window::INVISIBLE ),
556   mIsShowing( true ),
557   mIsAnimationPlaying( false ),
558   mCurrentSharedFile( 0 ),
559   mSharedBufferType( BUFFER_TYPE_SHM ),
560   mImpl( NULL ),
561   mBackgroundVisible( false ),
562   mTopMargin( 0 )
563 {
564   mIndicatorContentActor = Dali::Actor::New();
565   mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
566   mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
567
568   // Indicator image handles the touch event including "leave"
569   mIndicatorContentActor.SetLeaveRequired( true );
570   mIndicatorContentActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
571   mIndicatorContentActor.SetColor( Color::BLACK );
572
573   mIndicatorActor = Dali::Actor::New();
574   mIndicatorActor.Add( mIndicatorContentActor );
575
576   // Event handler to find out flick down gesture
577   mEventActor = Dali::Actor::New();
578   mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
579   mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
580   mIndicatorActor.Add( mEventActor );
581
582   // Attach pan gesture to find flick down during hiding.
583   // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
584   // since it consumes the pan gesture in advance.
585   mPanDetector = Dali::PanGestureDetector::New();
586   mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
587   mPanDetector.Attach( mEventActor );
588
589   Open( orientation );
590
591   // register indicator to accessibility adaptor
592   Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
593   if(accessibilityAdaptor)
594   {
595     AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
596   }
597   // hide the indicator by default
598   mIndicatorActor.SetVisible( false );
599
600   // create impl to handle ecore event
601   mImpl = new Impl(this);
602 }
603
604 Indicator::~Indicator()
605 {
606   if(mImpl)
607   {
608     delete mImpl;
609     mImpl = NULL;
610   }
611
612   if(mEventActor)
613   {
614     mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
615   }
616   Disconnect();
617 }
618
619 void Indicator::SetAdaptor(Adaptor* adaptor)
620 {
621   mAdaptor = adaptor;
622   mIndicatorBuffer->SetAdaptor( adaptor );
623 }
624
625 Dali::Actor Indicator::GetActor()
626 {
627   return mIndicatorActor;
628 }
629
630 void Indicator::Open( Dali::Window::WindowOrientation orientation )
631 {
632   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
633
634   // Calls from Window should be set up to ensure we are in a
635   // disconnected state before opening a second time.
636   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
637
638   mOrientation = orientation;
639
640   Connect();
641
642   // Change background visibility depending on orientation
643   if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE  )
644   {
645     if( mBackgroundRenderer )
646     {
647       mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
648       mBackgroundVisible = false;
649     }
650   }
651   else
652   {
653     SetOpacityMode( mOpacityMode );
654   }
655 }
656
657 void Indicator::Close()
658 {
659   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
660
661   if( mState == CONNECTED )
662   {
663     Disconnect();
664     if( mObserver != NULL )
665     {
666       mObserver->IndicatorClosed( this );
667     }
668   }
669
670   Dali::Texture emptyTexture;
671   SetForegroundImage( emptyTexture );
672 }
673
674 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
675 {
676   mOpacityMode = mode;
677
678   Dali::Geometry geometry = CreateBackgroundGeometry();
679   if( geometry )
680   {
681     if( mBackgroundRenderer )
682     {
683       if( mBackgroundRenderer.GetGeometry() != geometry )
684       {
685         mBackgroundRenderer.SetGeometry( geometry );
686       }
687     }
688     else
689     {
690       if( !mBackgroundShader )
691       {
692         mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
693       }
694
695       mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
696     }
697
698     if( !mBackgroundVisible )
699     {
700       mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
701       mBackgroundVisible = true;
702     }
703   }
704   else if( mBackgroundRenderer )
705   {
706     mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
707     mBackgroundVisible = false;
708   }
709   UpdateTopMargin();
710 }
711
712 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
713 {
714   if ( visibleMode != mVisible || forceUpdate )
715   {
716     // If we were previously hidden, then we should update the image data before we display the indicator
717     if ( mVisible == Dali::Window::INVISIBLE )
718     {
719       UpdateImageData( mCurrentSharedFile );
720     }
721
722     if ( visibleMode == Dali::Window::INVISIBLE )
723     {
724       if (mServerConnection)
725       {
726         mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
727       }
728     }
729     else
730     {
731       mIndicatorActor.SetVisible( true );
732
733       if( mServerConnection )
734       {
735          mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
736       }
737     }
738
739     mVisible = visibleMode;
740     UpdateTopMargin();
741
742     if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
743     {
744       if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
745       {
746         // hide indicator
747         ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
748       }
749       else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
750       {
751         // show indicator
752         ShowIndicator( KEEP_SHOWING );
753       }
754       else
755       {
756         // hide indicator
757         ShowIndicator( HIDE_NOW );
758       }
759     }
760     else
761     {
762       mIsShowing = false;
763     }
764   }
765 }
766
767 bool Indicator::IsConnected()
768 {
769   return ( mState == CONNECTED );
770 }
771
772 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
773 {
774  if(IsConnected())
775  {
776    return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
777  }
778  else
779  {
780    return false;
781  }
782 }
783
784 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
785 {
786   if( mServerConnection )
787   {
788     const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
789
790     // Send touch event to indicator server when indicator is showing
791     if( CheckVisibleState() || mIsShowing )
792     {
793       switch( touchPoint.state )
794       {
795         case Dali::PointState::DOWN:
796         {
797           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
798           IpcDataEvMouseDown ipcDown( touchEvent.time );
799           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
800           mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
801
802           if( mVisible == Dali::Window::AUTO )
803           {
804             // Stop hiding indicator
805             ShowIndicator( KEEP_SHOWING );
806           }
807         }
808         break;
809
810         case Dali::PointState::MOTION:
811         {
812           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
813           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
814         }
815         break;
816
817         case Dali::PointState::UP:
818         case Dali::PointState::INTERRUPTED:
819         {
820           IpcDataEvMouseUp ipcUp( touchEvent.time );
821           mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
822
823           if( mVisible == Dali::Window::AUTO )
824           {
825             // Hide indicator
826             ShowIndicator( 0.5f /* hide after 0.5 sec */ );
827           }
828         }
829         break;
830
831         case Dali::TouchPoint::Leave:
832         {
833           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
834           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
835           IpcDataEvMouseUp ipcOut( touchEvent.time );
836           mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
837         }
838         break;
839
840         default:
841           break;
842       }
843
844       return true;
845     }
846   }
847
848   return false;
849 }
850
851 bool Indicator::Connect()
852 {
853   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
854
855   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
856
857   bool connected = false;
858
859   mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
860   if( mServerConnection )
861   {
862     connected = mServerConnection->IsConnected();
863     if( ! connected )
864     {
865       delete mServerConnection;
866       mServerConnection = NULL;
867     }
868   }
869
870   if( !connected )
871   {
872     StartReconnectionTimer();
873   }
874   else
875   {
876     mState = CONNECTED;
877   }
878
879   return connected;
880 }
881
882 void Indicator::StartReconnectionTimer()
883 {
884   if( ! mReconnectTimer )
885   {
886     mReconnectTimer = Dali::Timer::New(1000);
887     mConnection.DisconnectAll();
888     mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
889   }
890   mReconnectTimer.Start();
891 }
892
893 bool Indicator::OnReconnectTimer()
894 {
895   bool retry = false;
896
897   if( mState == DISCONNECTED )
898   {
899     if( !Connect() )
900     {
901       retry = true;
902     }
903   }
904
905   return retry;
906 }
907
908 void Indicator::Disconnect()
909 {
910   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
911
912   mState = DISCONNECTED;
913
914   delete mServerConnection;
915   mServerConnection = NULL;
916
917   ClearSharedFileInfo();
918 }
919
920 void Indicator::Resize( int width, int height )
921 {
922   if( width < 1 )
923   {
924     width = 1;
925   }
926   if( height < 1 )
927   {
928     height = 1;
929   }
930
931   if( mImageWidth != width || mImageHeight != height )
932   {
933     mImageWidth = width;
934     mImageHeight = height;
935
936     mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
937     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
938     mEventActor.SetSize(mImageWidth, mImageHeight);
939     UpdateTopMargin();
940   }
941 }
942
943 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
944 {
945   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
946
947   // epcEvent->ref == w
948   // epcEvent->ref_to == h
949   // epcEvent->response == buffer num
950   // epcEvent->data = lockfile + nul byte
951
952   if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
953       (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
954   {
955     int n = epcEvent->response;
956
957     if( n >= 0 && n < SHARED_FILE_NUMBER )
958     {
959       mCurrentSharedFile = n;
960
961       mSharedFileInfo[n].mImageWidth  = epcEvent->ref;
962       mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
963
964       mSharedFileInfo[n].mLockFileName.clear();
965
966       mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
967
968       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
969                      n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
970     }
971   }
972 }
973
974 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
975 {
976   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
977
978   // epcEvent->ref == shm id
979   // epcEvent->ref_to == shm num
980   // epcEvent->response == buffer num
981   // epcEvent->data = shm ref string + nul byte
982
983   if ( (epcEvent->data) &&
984        (epcEvent->size > 0) &&
985        (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
986   {
987     int n = epcEvent->response;
988
989     if( n >= 0 && n < SHARED_FILE_NUMBER )
990     {
991       mCurrentSharedFile = n;
992
993       mSharedFileInfo[n].mSharedFileName.clear();
994
995       mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
996
997       mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
998       mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
999
1000       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
1001                      n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
1002     }
1003   }
1004 }
1005
1006 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1007 {
1008   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1009
1010   // epcEvent->ref == alpha
1011   // epcEvent->ref_to == sys
1012   // epcEvent->response == buffer num
1013
1014   if ( mSharedBufferType != BUFFER_TYPE_SHM )
1015   {
1016     return ;
1017   }
1018
1019   int n = epcEvent->response;
1020
1021   if( n >= 0 && n < SHARED_FILE_NUMBER )
1022   {
1023     mCurrentSharedFile = n;
1024
1025     delete mSharedFileInfo[n].mSharedFile;
1026     mSharedFileInfo[n].mSharedFile = NULL;
1027
1028     delete mSharedFileInfo[n].mLock;
1029     mSharedFileInfo[n].mLock = NULL;
1030
1031     std::stringstream sharedFileID;
1032     std::stringstream sharedFileNumber;
1033
1034     sharedFileID << mSharedFileInfo[n].mSharedFileID;
1035     sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
1036
1037     std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1038
1039     DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1040
1041     mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1042     if( mSharedFileInfo[n].mSharedFile != NULL )
1043     {
1044       mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
1045       if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1046       {
1047         DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1048       }
1049
1050       CreateNewImage( n );
1051       UpdateVisibility();
1052     }
1053   }
1054 }
1055
1056 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1057 {
1058   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1059
1060   // epcEvent->ref == pixmap id
1061   // epcEvent->ref_to == type
1062   // epcEvent->response == buffer num
1063
1064   if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
1065   {
1066     mSharedBufferType = (BufferType)(epcEvent->ref_to);
1067
1068     ClearSharedFileInfo();
1069
1070     mPixmap = static_cast<PixmapId>(epcEvent->ref);
1071     DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
1072
1073     CreateNewPixmapImage();
1074     UpdateVisibility();
1075   }
1076 }
1077
1078 void Indicator::UpdateTopMargin()
1079 {
1080   int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1081   if (mTopMargin != newMargin)
1082   {
1083     mTopMargin = newMargin;
1084     mAdaptor->IndicatorSizeChanged( mTopMargin );
1085   }
1086 }
1087
1088 void Indicator::UpdateVisibility()
1089 {
1090   if( CheckVisibleState() )
1091   {
1092     // set default indicator type (enable the quick panel)
1093     OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1094   }
1095   else
1096   {
1097     // set default indicator type (disable the quick panel)
1098     OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1099   }
1100
1101   if( !mIsShowing )
1102   {
1103     mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1104   }
1105
1106   SetVisible(mVisible, true);
1107 }
1108
1109 void Indicator::UpdateImageData( int bufferNumber )
1110 {
1111   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1112
1113   if( mState == CONNECTED && mVisible )
1114   {
1115     if(mPixmap == 0)
1116     {
1117       // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1118       CopyToBuffer( bufferNumber );
1119     }
1120     else
1121     {
1122       if(mIsShowing)
1123       {
1124         mAdaptor->RequestUpdateOnce();
1125       }
1126     }
1127   }
1128 }
1129
1130 bool Indicator::CopyToBuffer( int bufferNumber )
1131 {
1132   bool success = false;
1133
1134   if( mSharedFileInfo[bufferNumber].mLock )
1135   {
1136     Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1137     if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1138     {
1139       // Do nothing here.
1140     }
1141     else if( scopedLock.IsLocked() )
1142     {
1143       unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1144       size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1145
1146       if( mIndicatorBuffer->UpdatePixels( src, size ) )
1147       {
1148         mAdaptor->RequestUpdateOnce();
1149         success = true;
1150       }
1151     }
1152   }
1153
1154   return success;
1155 }
1156
1157 void Indicator::CreateNewPixmapImage()
1158 {
1159   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
1160   Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
1161
1162 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
1163   SaveIndicatorImage( nativeImageSource );
1164 #endif
1165
1166   if( nativeImageSource )
1167   {
1168     Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
1169     SetForegroundImage( texture );
1170     mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1171     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1172     mEventActor.SetSize( mImageWidth, mImageHeight );
1173     UpdateTopMargin();
1174   }
1175   else
1176   {
1177     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1178     Disconnect();
1179     if( mObserver != NULL )
1180     {
1181       mObserver->IndicatorClosed( this );
1182     }
1183     // Don't do connection in this callback - strange things happen!
1184     StartReconnectionTimer();
1185   }
1186 }
1187
1188 void Indicator::CreateNewImage( int bufferNumber )
1189 {
1190   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1191   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1192   bool success = false;
1193
1194   if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1195   {
1196     Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1197     if( texture )
1198     {
1199       SetForegroundImage( texture );
1200       success = true;
1201     }
1202   }
1203
1204   if( !success )
1205   {
1206     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1207     Disconnect();
1208     if( mObserver != NULL )
1209     {
1210       mObserver->IndicatorClosed( this );
1211     }
1212     // Don't do connection in this callback - strange things happen!
1213     StartReconnectionTimer();
1214   }
1215 }
1216
1217 Dali::Geometry Indicator::CreateBackgroundGeometry()
1218 {
1219   switch( mOpacityMode )
1220   {
1221     case Dali::Window::TRANSLUCENT:
1222       if( !mTranslucentGeometry )
1223       {
1224         // Construct 5 interval mesh
1225         // 0  +---+  1
1226         //    | \ |
1227         // 2  +---+  3
1228         //    | \ |
1229         // 4  +---+  5
1230         //    | \ |
1231         // 6  +---+  7
1232         //    | \ |
1233         // 8  +---+  9
1234         //    | \ |
1235         // 10 +---+  11
1236
1237         // Create vertices
1238         struct BackgroundVertex
1239         {
1240           Vector2 mPosition;
1241           float   mAlpha;
1242         };
1243
1244         unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1245         BackgroundVertex vertices[ numVertices ];
1246
1247         float d = -0.5f;
1248         float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1249         BackgroundVertex* currentVertex = vertices;
1250         for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1251         {
1252           currentVertex->mPosition = Vector2( -0.5f, d );
1253           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1254           currentVertex++;
1255
1256           currentVertex->mPosition = Vector2( 0.5f, d );
1257           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1258           currentVertex++;
1259         }
1260
1261         // Create indices
1262         unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1263         unsigned short indices[ numIndices ];
1264
1265         unsigned short* currentIndex = indices;
1266         for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1267         {
1268           *currentIndex++ = (2 * y);
1269           *currentIndex++ = (2 * y) + 3;
1270           *currentIndex++ = (2 * y) + 1;
1271
1272           *currentIndex++ = (2 * y);
1273           *currentIndex++ = (2 * y) + 2;
1274           *currentIndex++ = (2 * y) + 3;
1275         }
1276
1277         Dali::Property::Map vertexFormat;
1278         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1279         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1280         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1281         vertexPropertyBuffer.SetData( vertices, numVertices );
1282
1283         // Create the geometry object
1284         mTranslucentGeometry = Dali::Geometry::New();
1285         mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1286         mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1287       }
1288
1289       return mTranslucentGeometry;
1290     case Dali::Window::OPAQUE:
1291
1292       if( !mSolidGeometry )
1293       {
1294         // Create vertices
1295         struct BackgroundVertex
1296         {
1297           Vector2 mPosition;
1298           float   mAlpha;
1299         };
1300
1301         BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1302                                            { Vector2( -0.5f,  0.5f ), 1.0f }, { Vector2( 0.5f,  0.5f ), 1.0f } };
1303
1304         // Create indices
1305         unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1306
1307         Dali::Property::Map vertexFormat;
1308         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1309         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1310         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1311         vertexPropertyBuffer.SetData( vertices, 4 );
1312
1313
1314         // Create the geometry object
1315         mSolidGeometry = Dali::Geometry::New();
1316         mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1317         mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1318       }
1319
1320       return mSolidGeometry;
1321     case Dali::Window::TRANSPARENT:
1322       break;
1323   }
1324
1325   return Dali::Geometry();
1326 }
1327
1328 void Indicator::SetForegroundImage( Dali::Texture texture )
1329 {
1330   if( !mForegroundRenderer && texture )
1331   {
1332     // Create Shader
1333     Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1334
1335     // Create renderer from geometry and material
1336     Dali::Geometry quad = CreateQuadGeometry();
1337     mForegroundRenderer = Dali::Renderer::New( quad, shader );
1338     // Make sure the foreground stays in front of the background
1339     mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1340
1341     // Set blend function
1342     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB,    Dali::BlendFactor::ONE );
1343     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB,   Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1344     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  Dali::BlendFactor::ONE );
1345     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1346
1347     // Create a texture-set and add to renderer
1348
1349     Dali::TextureSet textureSet = Dali::TextureSet::New();
1350     textureSet.SetTexture( 0u, texture );
1351     mForegroundRenderer.SetTextures( textureSet );
1352
1353     mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1354   }
1355   else if( mForegroundRenderer )
1356   {
1357     Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1358     textureSet.SetTexture( 0u, texture );
1359   }
1360
1361   if( mImageWidth == 0 && mImageHeight == 0  && texture)
1362   {
1363     Resize( texture.GetWidth(), texture.GetHeight() );
1364   }
1365 }
1366
1367 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1368 {
1369   if( mObserver != NULL )
1370   {
1371     mObserver->IndicatorTypeChanged( indicatorType );
1372   }
1373 }
1374
1375 void Indicator::DataReceived( void* event )
1376 {
1377   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1378   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1379
1380   switch( epcEvent->minor )
1381   {
1382     case OP_UPDATE:
1383     {
1384       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1385       if( mIsShowing )
1386       {
1387         mAdaptor->RequestUpdateOnce();
1388       }
1389       break;
1390     }
1391     case OP_UPDATE_DONE:
1392     {
1393       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1394       // epcEvent->response == display buffer #
1395       UpdateImageData( epcEvent->response );
1396       break;
1397     }
1398     case OP_SHM_REF0:
1399     {
1400       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1401       SetSharedImageInfo( epcEvent );
1402       break;
1403     }
1404     case OP_SHM_REF1:
1405     {
1406       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1407       SetLockFileInfo( epcEvent );
1408       break;
1409     }
1410     case OP_SHM_REF2:
1411     {
1412       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1413       LoadSharedImage( epcEvent );
1414       break;
1415     }
1416     case OP_PIXMAP_REF:
1417     {
1418       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1419       LoadPixmapImage( epcEvent );
1420       break;
1421     }
1422     case OP_RESIZE:
1423     {
1424       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1425
1426       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1427       {
1428         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1429         Resize( newSize->w, newSize->h );
1430       }
1431       break;
1432     }
1433     case OP_MSG_PARENT:
1434     {
1435       int msgDomain = epcEvent->ref;
1436       int msgId = epcEvent->ref_to;
1437
1438       void *msgData = NULL;
1439       int msgDataSize = 0;
1440       msgData = epcEvent->data;
1441       msgDataSize = epcEvent->size;
1442
1443       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1444
1445       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1446       {
1447         switch( msgId )
1448         {
1449           case MSG_ID_INDICATOR_TYPE:
1450           {
1451             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1452             Type* indicatorType = static_cast<Type*>( epcEvent->data );
1453             OnIndicatorTypeChanged( *indicatorType );
1454             break;
1455           }
1456
1457           case MSG_ID_INDICATOR_START_ANIMATION:
1458           {
1459             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1460
1461             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1462             {
1463               DALI_LOG_ERROR("Message data is incorrect\n");
1464               break;
1465             }
1466
1467             IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1468
1469             if(!CheckVisibleState())
1470             {
1471               ShowIndicator( animData->duration /* n sec */ );
1472             }
1473             break;
1474           }
1475         }
1476       }
1477       break;
1478     }
1479   }
1480 }
1481
1482 void Indicator::ConnectionClosed()
1483 {
1484   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1485
1486   // Will get this callback if the server connection failed to start up.
1487   delete mServerConnection;
1488   mServerConnection = NULL;
1489   mState = DISCONNECTED;
1490
1491   // Attempt to re-connect
1492   Connect();
1493 }
1494
1495 bool Indicator::CheckVisibleState()
1496 {
1497   if( mOrientation == Dali::Window::LANDSCAPE
1498     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1499     || (mVisible == Dali::Window::INVISIBLE)
1500     || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1501   {
1502     return false;
1503   }
1504
1505   return true;
1506 }
1507
1508 void Indicator::ClearSharedFileInfo()
1509 {
1510   for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1511   {
1512     delete mSharedFileInfo[i].mLock;
1513     mSharedFileInfo[i].mLock = NULL;
1514
1515     delete mSharedFileInfo[i].mSharedFile;
1516     mSharedFileInfo[i].mSharedFile = NULL;
1517
1518     mSharedFileInfo[i].mLockFileName.clear();
1519     mSharedFileInfo[i].mSharedFileName.clear();
1520   }
1521 }
1522
1523 /**
1524  * duration can be this
1525  *
1526  * enum
1527  * {
1528  *  KEEP_SHOWING = -1,
1529  *  HIDE_NOW = 0
1530  * };
1531  */
1532 void Indicator::ShowIndicator(float duration)
1533 {
1534   if( !mIndicatorAnimation )
1535   {
1536     mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1537     mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1538   }
1539
1540   if(mIsShowing && !EqualsZero(duration))
1541   {
1542     // If need to show during showing, do nothing.
1543     // In 2nd phase (below) will update timer
1544   }
1545   else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1546   {
1547     // If need to hide during hiding or hidden already, do nothing
1548   }
1549   else
1550   {
1551     mIndicatorAnimation.Clear();
1552
1553     if( EqualsZero(duration) )
1554     {
1555       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1556
1557       mIsShowing = false;
1558
1559       OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1560     }
1561     else
1562     {
1563       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1564
1565       mIsShowing = true;
1566
1567       OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1568     }
1569
1570     mIndicatorAnimation.Play();
1571     mIsAnimationPlaying = true;
1572   }
1573
1574   if(duration > 0)
1575   {
1576     if(!mShowTimer)
1577     {
1578       mShowTimer = Dali::Timer::New(1000 * duration);
1579       mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1580     }
1581     mShowTimer.SetInterval(1000* duration);
1582     mShowTimer.Start();
1583
1584     if( mVisible == Dali::Window::AUTO )
1585     {
1586       // check the stage touch
1587       Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1588     }
1589   }
1590   else
1591   {
1592     if(mShowTimer && mShowTimer.IsRunning())
1593     {
1594       mShowTimer.Stop();
1595     }
1596
1597     if( mVisible == Dali::Window::AUTO )
1598     {
1599       // check the stage touch
1600       Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1601     }
1602   }
1603 }
1604
1605 bool Indicator::OnShowTimer()
1606 {
1607   // after time up, hide indicator
1608   ShowIndicator( HIDE_NOW );
1609
1610   return false;
1611 }
1612
1613 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1614 {
1615   mIsAnimationPlaying = false;
1616   // once animation is finished and indicator is hidden, take it off stage
1617   if( mObserver != NULL )
1618   {
1619     mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1620   }
1621 }
1622
1623 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1624 {
1625   // Nothing to do, but we still want to consume pan
1626 }
1627
1628 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1629 {
1630   const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1631
1632   // when stage is touched while indicator is showing temporary, hide it
1633   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1634   {
1635     switch( touchPoint.state )
1636     {
1637       case Dali::PointState::DOWN:
1638       {
1639         // if touch point is inside the indicator, indicator is not hidden
1640         if( mImageHeight < int(touchPoint.screen.y) )
1641         {
1642           ShowIndicator( HIDE_NOW );
1643         }
1644         break;
1645       }
1646
1647       default:
1648       break;
1649     }
1650   }
1651 }
1652
1653 } // Adaptor
1654 } // Internal
1655 } // Dali