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