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