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