Merge "Add texture target for OES_EGL_image_external" into devel/master
[platform/core/uifw/dali-adaptor.git] / adaptors / ecore / common / ecore-indicator-impl.cpp
1 /*
2  * Copyright (c) 2014 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   mGestureDetected( false ),
545   mConnection( this ),
546   mOpacityMode( Dali::Window::OPAQUE ),
547   mState( DISCONNECTED ),
548   mAdaptor(adaptor),
549   mServerConnection( NULL ),
550   mObserver( observer ),
551   mOrientation( orientation ),
552   mImageWidth( 0 ),
553   mImageHeight( 0 ),
554   mVisible( Dali::Window::INVISIBLE ),
555   mIsShowing( true ),
556   mIsAnimationPlaying( false ),
557   mCurrentSharedFile( 0 ),
558   mSharedBufferType( BUFFER_TYPE_SHM ),
559   mImpl( NULL ),
560   mBackgroundVisible( false )
561 {
562   mIndicatorContentActor = Dali::Actor::New();
563   mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
564   mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
565
566   // Indicator image handles the touch event including "leave"
567   mIndicatorContentActor.SetLeaveRequired( true );
568   mIndicatorContentActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
569   mIndicatorContentActor.SetColor( Color::BLACK );
570
571   mIndicatorActor = Dali::Actor::New();
572   mIndicatorActor.Add( mIndicatorContentActor );
573
574   // Event handler to find out flick down gesture
575   mEventActor = Dali::Actor::New();
576   mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
577   mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
578   mIndicatorActor.Add( mEventActor );
579
580   // Attach pan gesture to find flick down during hiding.
581   // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
582   // since it consumes the pan gesture in advance.
583   mPanDetector = Dali::PanGestureDetector::New();
584   mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
585   mPanDetector.Attach( mEventActor );
586
587   Open( orientation );
588
589   // register indicator to accessibility adaptor
590   Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
591   if(accessibilityAdaptor)
592   {
593     AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
594   }
595   // hide the indicator by default
596   mIndicatorActor.SetVisible( false );
597
598   // create impl to handle ecore event
599   mImpl = new Impl(this);
600 }
601
602 Indicator::~Indicator()
603 {
604   if(mImpl)
605   {
606     delete mImpl;
607     mImpl = NULL;
608   }
609
610   if(mEventActor)
611   {
612     mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
613   }
614   Disconnect();
615 }
616
617 void Indicator::SetAdaptor(Adaptor* adaptor)
618 {
619   mAdaptor = adaptor;
620   mIndicatorBuffer->SetAdaptor( adaptor );
621 }
622
623 Dali::Actor Indicator::GetActor()
624 {
625   return mIndicatorActor;
626 }
627
628 void Indicator::Open( Dali::Window::WindowOrientation orientation )
629 {
630   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
631
632   // Calls from Window should be set up to ensure we are in a
633   // disconnected state before opening a second time.
634   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
635
636   mOrientation = orientation;
637
638   Connect();
639
640   // Change background visibility depending on orientation
641   if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE  )
642   {
643     if( mBackgroundRenderer )
644     {
645       mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
646       mBackgroundVisible = false;
647     }
648   }
649   else
650   {
651     SetOpacityMode( mOpacityMode );
652   }
653 }
654
655 void Indicator::Close()
656 {
657   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
658
659   if( mState == CONNECTED )
660   {
661     Disconnect();
662     if( mObserver != NULL )
663     {
664       mObserver->IndicatorClosed( this );
665     }
666   }
667
668   Dali::Texture emptyTexture;
669   SetForegroundImage( emptyTexture );
670 }
671
672 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
673 {
674   mOpacityMode = mode;
675
676   Dali::Geometry geometry = CreateBackgroundGeometry();
677   if( geometry )
678   {
679     if( mBackgroundRenderer )
680     {
681       if( mBackgroundRenderer.GetGeometry() != geometry )
682       {
683         mBackgroundRenderer.SetGeometry( geometry );
684       }
685     }
686     else
687     {
688       if( !mBackgroundShader )
689       {
690         mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
691       }
692
693       mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
694     }
695
696     if( !mBackgroundVisible )
697     {
698       mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
699       mBackgroundVisible = true;
700     }
701   }
702   else if( mBackgroundRenderer )
703   {
704     mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
705     mBackgroundVisible = false;
706   }
707 }
708
709 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
710 {
711   if ( visibleMode != mVisible || forceUpdate )
712   {
713     // If we were previously hidden, then we should update the image data before we display the indicator
714     if ( mVisible == Dali::Window::INVISIBLE )
715     {
716       UpdateImageData( mCurrentSharedFile );
717     }
718
719     if ( visibleMode == Dali::Window::INVISIBLE )
720     {
721       if (mServerConnection)
722       {
723         mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
724       }
725     }
726     else
727     {
728       mIndicatorActor.SetVisible( true );
729
730       if( mServerConnection )
731       {
732          mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
733       }
734     }
735
736     mVisible = visibleMode;
737
738     if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
739     {
740       if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
741       {
742         // hide indicator
743         ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
744       }
745       else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
746       {
747         // show indicator
748         ShowIndicator( KEEP_SHOWING );
749       }
750       else
751       {
752         // hide indicator
753         ShowIndicator( HIDE_NOW );
754       }
755     }
756     else
757     {
758       mIsShowing = false;
759     }
760   }
761 }
762
763 bool Indicator::IsConnected()
764 {
765   return ( mState == CONNECTED );
766 }
767
768 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
769 {
770  if(IsConnected())
771  {
772    return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
773  }
774  else
775  {
776    return false;
777  }
778 }
779
780 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
781 {
782   if( mServerConnection )
783   {
784     const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
785
786     // Send touch event to indicator server when indicator is showing
787     if( CheckVisibleState() || mIsShowing )
788     {
789       switch( touchPoint.state )
790       {
791         case Dali::PointState::DOWN:
792         {
793           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
794           IpcDataEvMouseDown ipcDown( touchEvent.time );
795           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
796           mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
797
798           if( mVisible == Dali::Window::AUTO )
799           {
800             // Stop hiding indicator
801             ShowIndicator( KEEP_SHOWING );
802           }
803         }
804         break;
805
806         case Dali::PointState::MOTION:
807         {
808           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
809           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
810         }
811         break;
812
813         case Dali::PointState::UP:
814         case Dali::PointState::INTERRUPTED:
815         {
816           IpcDataEvMouseUp ipcUp( touchEvent.time );
817           mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
818
819           if( mVisible == Dali::Window::AUTO )
820           {
821             // Hide indicator
822             ShowIndicator( 0.5f /* hide after 0.5 sec */ );
823           }
824         }
825         break;
826
827         case Dali::TouchPoint::Leave:
828         {
829           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
830           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
831           IpcDataEvMouseUp ipcOut( touchEvent.time );
832           mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
833         }
834         break;
835
836         default:
837           break;
838       }
839
840       return true;
841     }
842   }
843
844   return false;
845 }
846
847 bool Indicator::Connect()
848 {
849   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
850
851   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
852
853   bool connected = false;
854
855   mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
856   if( mServerConnection )
857   {
858     connected = mServerConnection->IsConnected();
859     if( ! connected )
860     {
861       delete mServerConnection;
862       mServerConnection = NULL;
863     }
864   }
865
866   if( !connected )
867   {
868     StartReconnectionTimer();
869   }
870   else
871   {
872     mState = CONNECTED;
873   }
874
875   return connected;
876 }
877
878 void Indicator::StartReconnectionTimer()
879 {
880   if( ! mReconnectTimer )
881   {
882     mReconnectTimer = Dali::Timer::New(1000);
883     mConnection.DisconnectAll();
884     mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
885   }
886   mReconnectTimer.Start();
887 }
888
889 bool Indicator::OnReconnectTimer()
890 {
891   bool retry = false;
892
893   if( mState == DISCONNECTED )
894   {
895     if( !Connect() )
896     {
897       retry = true;
898     }
899   }
900
901   return retry;
902 }
903
904 void Indicator::Disconnect()
905 {
906   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
907
908   mState = DISCONNECTED;
909
910   delete mServerConnection;
911   mServerConnection = NULL;
912
913   ClearSharedFileInfo();
914 }
915
916 void Indicator::Resize( int width, int height )
917 {
918   if( width < 1 )
919   {
920     width = 1;
921   }
922   if( height < 1 )
923   {
924     height = 1;
925   }
926
927   if( mImageWidth != width || mImageHeight != height )
928   {
929     mImageWidth = width;
930     mImageHeight = height;
931
932     mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
933     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
934     mEventActor.SetSize(mImageWidth, mImageHeight);
935   }
936 }
937
938 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
939 {
940   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
941
942   // epcEvent->ref == w
943   // epcEvent->ref_to == h
944   // epcEvent->response == buffer num
945   // epcEvent->data = lockfile + nul byte
946
947   if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
948       (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
949   {
950     int n = epcEvent->response;
951
952     if( n >= 0 && n < SHARED_FILE_NUMBER )
953     {
954       mCurrentSharedFile = n;
955
956       mSharedFileInfo[n].mImageWidth  = epcEvent->ref;
957       mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
958
959       mSharedFileInfo[n].mLockFileName.clear();
960
961       mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
962
963       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
964                      n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
965     }
966   }
967 }
968
969 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
970 {
971   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
972
973   // epcEvent->ref == shm id
974   // epcEvent->ref_to == shm num
975   // epcEvent->response == buffer num
976   // epcEvent->data = shm ref string + nul byte
977
978   if ( (epcEvent->data) &&
979        (epcEvent->size > 0) &&
980        (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
981   {
982     int n = epcEvent->response;
983
984     if( n >= 0 && n < SHARED_FILE_NUMBER )
985     {
986       mCurrentSharedFile = n;
987
988       mSharedFileInfo[n].mSharedFileName.clear();
989
990       mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
991
992       mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
993       mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
994
995       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
996                      n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
997     }
998   }
999 }
1000
1001 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1002 {
1003   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1004
1005   // epcEvent->ref == alpha
1006   // epcEvent->ref_to == sys
1007   // epcEvent->response == buffer num
1008
1009   if ( mSharedBufferType != BUFFER_TYPE_SHM )
1010   {
1011     return ;
1012   }
1013
1014   int n = epcEvent->response;
1015
1016   if( n >= 0 && n < SHARED_FILE_NUMBER )
1017   {
1018     mCurrentSharedFile = n;
1019
1020     delete mSharedFileInfo[n].mSharedFile;
1021     mSharedFileInfo[n].mSharedFile = NULL;
1022
1023     delete mSharedFileInfo[n].mLock;
1024     mSharedFileInfo[n].mLock = NULL;
1025
1026     std::stringstream sharedFileID;
1027     std::stringstream sharedFileNumber;
1028
1029     sharedFileID << mSharedFileInfo[n].mSharedFileID;
1030     sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
1031
1032     std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1033
1034     DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1035
1036     mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1037     if( mSharedFileInfo[n].mSharedFile != NULL )
1038     {
1039       mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
1040       if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1041       {
1042         DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1043       }
1044
1045       CreateNewImage( n );
1046       UpdateVisibility();
1047     }
1048   }
1049 }
1050
1051 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1052 {
1053   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1054
1055   // epcEvent->ref == pixmap id
1056   // epcEvent->ref_to == type
1057   // epcEvent->response == buffer num
1058
1059   if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
1060   {
1061     mSharedBufferType = (BufferType)(epcEvent->ref_to);
1062
1063     ClearSharedFileInfo();
1064
1065     mPixmap = static_cast<PixmapId>(epcEvent->ref);
1066     DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
1067
1068     CreateNewPixmapImage();
1069     UpdateVisibility();
1070   }
1071 }
1072
1073 void Indicator::UpdateVisibility()
1074 {
1075   if( CheckVisibleState() )
1076   {
1077     // set default indicator type (enable the quick panel)
1078     OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1079   }
1080   else
1081   {
1082     // set default indicator type (disable the quick panel)
1083     OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1084   }
1085
1086   if( !mIsShowing )
1087   {
1088     mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1089   }
1090
1091   SetVisible(mVisible, true);
1092 }
1093
1094 void Indicator::UpdateImageData( int bufferNumber )
1095 {
1096   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1097
1098   if( mState == CONNECTED && mVisible )
1099   {
1100     if(mPixmap == 0)
1101     {
1102       // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1103       CopyToBuffer( bufferNumber );
1104     }
1105     else
1106     {
1107       if(mIsShowing)
1108       {
1109         mAdaptor->RequestUpdateOnce();
1110       }
1111     }
1112   }
1113 }
1114
1115 bool Indicator::CopyToBuffer( int bufferNumber )
1116 {
1117   bool success = false;
1118
1119   if( mSharedFileInfo[bufferNumber].mLock )
1120   {
1121     Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1122     if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1123     {
1124       // Do nothing here.
1125     }
1126     else if( scopedLock.IsLocked() )
1127     {
1128       unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1129       size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1130
1131       if( mIndicatorBuffer->UpdatePixels( src, size ) )
1132       {
1133         mAdaptor->RequestUpdateOnce();
1134         success = true;
1135       }
1136     }
1137   }
1138
1139   return success;
1140 }
1141
1142 void Indicator::CreateNewPixmapImage()
1143 {
1144   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
1145   Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
1146
1147 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
1148   SaveIndicatorImage( nativeImageSource );
1149 #endif
1150
1151   if( nativeImageSource )
1152   {
1153     Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
1154     SetForegroundImage( texture );
1155     mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1156     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1157     mEventActor.SetSize( mImageWidth, mImageHeight );
1158   }
1159   else
1160   {
1161     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1162     Disconnect();
1163     if( mObserver != NULL )
1164     {
1165       mObserver->IndicatorClosed( this );
1166     }
1167     // Don't do connection in this callback - strange things happen!
1168     StartReconnectionTimer();
1169   }
1170 }
1171
1172 void Indicator::CreateNewImage( int bufferNumber )
1173 {
1174   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1175   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1176   bool success = false;
1177
1178   if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1179   {
1180     Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1181     if( texture )
1182     {
1183       SetForegroundImage( texture );
1184       success = true;
1185     }
1186   }
1187
1188   if( !success )
1189   {
1190     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1191     Disconnect();
1192     if( mObserver != NULL )
1193     {
1194       mObserver->IndicatorClosed( this );
1195     }
1196     // Don't do connection in this callback - strange things happen!
1197     StartReconnectionTimer();
1198   }
1199 }
1200
1201 Dali::Geometry Indicator::CreateBackgroundGeometry()
1202 {
1203   switch( mOpacityMode )
1204   {
1205     case Dali::Window::TRANSLUCENT:
1206       if( !mTranslucentGeometry )
1207       {
1208         // Construct 5 interval mesh
1209         // 0  +---+  1
1210         //    | \ |
1211         // 2  +---+  3
1212         //    | \ |
1213         // 4  +---+  5
1214         //    | \ |
1215         // 6  +---+  7
1216         //    | \ |
1217         // 8  +---+  9
1218         //    | \ |
1219         // 10 +---+  11
1220
1221         // Create vertices
1222         struct BackgroundVertex
1223         {
1224           Vector2 mPosition;
1225           float   mAlpha;
1226         };
1227
1228         unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1229         BackgroundVertex vertices[ numVertices ];
1230
1231         float d = -0.5f;
1232         float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1233         BackgroundVertex* currentVertex = vertices;
1234         for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1235         {
1236           currentVertex->mPosition = Vector2( -0.5f, d );
1237           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1238           currentVertex++;
1239
1240           currentVertex->mPosition = Vector2( 0.5f, d );
1241           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1242           currentVertex++;
1243         }
1244
1245         // Create indices
1246         unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1247         unsigned short indices[ numIndices ];
1248
1249         unsigned short* currentIndex = indices;
1250         for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1251         {
1252           *currentIndex++ = (2 * y);
1253           *currentIndex++ = (2 * y) + 3;
1254           *currentIndex++ = (2 * y) + 1;
1255
1256           *currentIndex++ = (2 * y);
1257           *currentIndex++ = (2 * y) + 2;
1258           *currentIndex++ = (2 * y) + 3;
1259         }
1260
1261         Dali::Property::Map vertexFormat;
1262         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1263         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1264         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1265         vertexPropertyBuffer.SetData( vertices, numVertices );
1266
1267         // Create the geometry object
1268         mTranslucentGeometry = Dali::Geometry::New();
1269         mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1270         mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1271       }
1272
1273       return mTranslucentGeometry;
1274     case Dali::Window::OPAQUE:
1275
1276       if( !mSolidGeometry )
1277       {
1278         // Create vertices
1279         struct BackgroundVertex
1280         {
1281           Vector2 mPosition;
1282           float   mAlpha;
1283         };
1284
1285         BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1286                                            { Vector2( -0.5f,  0.5f ), 1.0f }, { Vector2( 0.5f,  0.5f ), 1.0f } };
1287
1288         // Create indices
1289         unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1290
1291         Dali::Property::Map vertexFormat;
1292         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1293         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1294         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1295         vertexPropertyBuffer.SetData( vertices, 4 );
1296
1297
1298         // Create the geometry object
1299         mSolidGeometry = Dali::Geometry::New();
1300         mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1301         mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1302       }
1303
1304       return mSolidGeometry;
1305     case Dali::Window::TRANSPARENT:
1306       break;
1307   }
1308
1309   return Dali::Geometry();
1310 }
1311
1312 void Indicator::SetForegroundImage( Dali::Texture texture )
1313 {
1314   if( !mForegroundRenderer && texture )
1315   {
1316     // Create Shader
1317     Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1318
1319     // Create renderer from geometry and material
1320     Dali::Geometry quad = CreateQuadGeometry();
1321     mForegroundRenderer = Dali::Renderer::New( quad, shader );
1322     // Make sure the foreground stays in front of the background
1323     mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1324
1325     // Set blend function
1326     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB,    Dali::BlendFactor::ONE );
1327     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB,   Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1328     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  Dali::BlendFactor::ONE );
1329     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1330
1331     // Create a texture-set and add to renderer
1332
1333     Dali::TextureSet textureSet = Dali::TextureSet::New();
1334     textureSet.SetTexture( 0u, texture );
1335     mForegroundRenderer.SetTextures( textureSet );
1336
1337     mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1338   }
1339   else if( mForegroundRenderer )
1340   {
1341     Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1342     textureSet.SetTexture( 0u, texture );
1343   }
1344
1345   if( mImageWidth == 0 && mImageHeight == 0  && texture)
1346   {
1347     Resize( texture.GetWidth(), texture.GetHeight() );
1348   }
1349 }
1350
1351 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1352 {
1353   if( mObserver != NULL )
1354   {
1355     mObserver->IndicatorTypeChanged( indicatorType );
1356   }
1357 }
1358
1359 void Indicator::DataReceived( void* event )
1360 {
1361   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1362   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1363
1364   switch( epcEvent->minor )
1365   {
1366     case OP_UPDATE:
1367     {
1368       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1369       if( mIsShowing )
1370       {
1371         //mAdaptor->RequestUpdateOnce();
1372       }
1373       break;
1374     }
1375     case OP_UPDATE_DONE:
1376     {
1377       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1378       // epcEvent->response == display buffer #
1379       //UpdateImageData( epcEvent->response );
1380       break;
1381     }
1382     case OP_SHM_REF0:
1383     {
1384       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1385       SetSharedImageInfo( epcEvent );
1386       break;
1387     }
1388     case OP_SHM_REF1:
1389     {
1390       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1391       SetLockFileInfo( epcEvent );
1392       break;
1393     }
1394     case OP_SHM_REF2:
1395     {
1396       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1397       LoadSharedImage( epcEvent );
1398       break;
1399     }
1400     case OP_PIXMAP_REF:
1401     {
1402       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1403       LoadPixmapImage( epcEvent );
1404       break;
1405     }
1406     case OP_RESIZE:
1407     {
1408       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1409
1410       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1411       {
1412         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1413         Resize( newSize->w, newSize->h );
1414       }
1415       break;
1416     }
1417     case OP_MSG_PARENT:
1418     {
1419       int msgDomain = epcEvent->ref;
1420       int msgId = epcEvent->ref_to;
1421
1422       void *msgData = NULL;
1423       int msgDataSize = 0;
1424       msgData = epcEvent->data;
1425       msgDataSize = epcEvent->size;
1426
1427       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1428
1429       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1430       {
1431         switch( msgId )
1432         {
1433           case MSG_ID_INDICATOR_TYPE:
1434           {
1435             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1436             Type* indicatorType = static_cast<Type*>( epcEvent->data );
1437             OnIndicatorTypeChanged( *indicatorType );
1438             break;
1439           }
1440
1441           case MSG_ID_INDICATOR_START_ANIMATION:
1442           {
1443             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1444
1445             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1446             {
1447               DALI_LOG_ERROR("Message data is incorrect\n");
1448               break;
1449             }
1450
1451             IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1452
1453             if(!CheckVisibleState())
1454             {
1455               ShowIndicator( animData->duration /* n sec */ );
1456             }
1457             break;
1458           }
1459         }
1460       }
1461       break;
1462     }
1463   }
1464 }
1465
1466 void Indicator::ConnectionClosed()
1467 {
1468   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1469
1470   // Will get this callback if the server connection failed to start up.
1471   delete mServerConnection;
1472   mServerConnection = NULL;
1473   mState = DISCONNECTED;
1474
1475   // Attempt to re-connect
1476   Connect();
1477 }
1478
1479 bool Indicator::CheckVisibleState()
1480 {
1481   if( mOrientation == Dali::Window::LANDSCAPE
1482     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1483     || (mVisible == Dali::Window::INVISIBLE)
1484     || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1485   {
1486     return false;
1487   }
1488
1489   return true;
1490 }
1491
1492 void Indicator::ClearSharedFileInfo()
1493 {
1494   for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1495   {
1496     delete mSharedFileInfo[i].mLock;
1497     mSharedFileInfo[i].mLock = NULL;
1498
1499     delete mSharedFileInfo[i].mSharedFile;
1500     mSharedFileInfo[i].mSharedFile = NULL;
1501
1502     mSharedFileInfo[i].mLockFileName.clear();
1503     mSharedFileInfo[i].mSharedFileName.clear();
1504   }
1505 }
1506
1507 /**
1508  * duration can be this
1509  *
1510  * enum
1511  * {
1512  *  KEEP_SHOWING = -1,
1513  *  HIDE_NOW = 0
1514  * };
1515  */
1516 void Indicator::ShowIndicator(float duration)
1517 {
1518   if( !mIndicatorAnimation )
1519   {
1520     mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1521     mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1522   }
1523
1524   if(mIsShowing && !EqualsZero(duration))
1525   {
1526     // If need to show during showing, do nothing.
1527     // In 2nd phase (below) will update timer
1528   }
1529   else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1530   {
1531     // If need to hide during hiding or hidden already, do nothing
1532   }
1533   else
1534   {
1535     mIndicatorAnimation.Clear();
1536
1537     if( EqualsZero(duration) )
1538     {
1539       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1540
1541       mIsShowing = false;
1542
1543       OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1544     }
1545     else
1546     {
1547       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1548
1549       mIsShowing = true;
1550
1551       OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1552     }
1553
1554     mIndicatorAnimation.Play();
1555     mIsAnimationPlaying = true;
1556   }
1557
1558   if(duration > 0)
1559   {
1560     if(!mShowTimer)
1561     {
1562       mShowTimer = Dali::Timer::New(1000 * duration);
1563       mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1564     }
1565     mShowTimer.SetInterval(1000* duration);
1566     mShowTimer.Start();
1567
1568     if( mVisible == Dali::Window::AUTO )
1569     {
1570       // check the stage touch
1571       Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1572     }
1573   }
1574   else
1575   {
1576     if(mShowTimer && mShowTimer.IsRunning())
1577     {
1578       mShowTimer.Stop();
1579     }
1580
1581     if( mVisible == Dali::Window::AUTO )
1582     {
1583       // check the stage touch
1584       Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1585     }
1586   }
1587 }
1588
1589 bool Indicator::OnShowTimer()
1590 {
1591   // after time up, hide indicator
1592   ShowIndicator( HIDE_NOW );
1593
1594   return false;
1595 }
1596
1597 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1598 {
1599   mIsAnimationPlaying = false;
1600   // once animation is finished and indicator is hidden, take it off stage
1601   if( mObserver != NULL )
1602   {
1603     mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1604   }
1605 }
1606
1607 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1608 {
1609   return ;
1610
1611   if( mServerConnection )
1612   {
1613     switch( gesture.state )
1614     {
1615       case Gesture::Started:
1616       {
1617         mGestureDetected = false;
1618
1619         // The gesture position is the current position after it has moved by the displacement.
1620         // We want to reference the original position.
1621         mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1622       }
1623
1624       // No break, Fall through
1625       case Gesture::Continuing:
1626       {
1627         if( mVisible == Dali::Window::AUTO && !mIsShowing )
1628         {
1629           // Only take one touch point
1630           if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1631           {
1632             mGestureDeltaY += gesture.displacement.y;
1633
1634             if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1635             {
1636               ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1637               mGestureDetected = true;
1638             }
1639           }
1640         }
1641
1642         break;
1643       }
1644
1645       case Gesture::Finished:
1646       case Gesture::Cancelled:
1647       {
1648         // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1649         if( mVisible == Dali::Window::AUTO && mIsShowing )
1650         {
1651           ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1652         }
1653         break;
1654       }
1655
1656
1657       default:
1658         break;
1659     }
1660   }
1661 }
1662
1663 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1664 {
1665   const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1666
1667   // when stage is touched while indicator is showing temporary, hide it
1668   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1669   {
1670     switch( touchPoint.state )
1671     {
1672       case Dali::PointState::DOWN:
1673       {
1674         // if touch point is inside the indicator, indicator is not hidden
1675         if( mImageHeight < int(touchPoint.screen.y) )
1676         {
1677           ShowIndicator( HIDE_NOW );
1678         }
1679         break;
1680       }
1681
1682       default:
1683       break;
1684     }
1685   }
1686 }
1687
1688 } // Adaptor
1689 } // Internal
1690 } // Dali