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