Merge "Make ecore-indicator-impl use TouchSignal instead of TouchedSignal" into devel...
[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::Vector2& touchPoint, unsigned long timestamp)
260   : x(static_cast<Evas_Coord>(touchPoint.x)),
261     y(static_cast<Evas_Coord>(touchPoint.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.TouchSignal().Connect( this, &Indicator::OnTouch );
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.TouchSignal().Disconnect( this, &Indicator::OnTouch );
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::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
793 {
794   if( mServerConnection )
795   {
796     // Send touch event to indicator server when indicator is showing
797     if( CheckVisibleState() || mIsShowing )
798     {
799       switch( touchData.GetState(0) )
800       {
801         case Dali::PointState::DOWN:
802         {
803           IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
804           IpcDataEvMouseDown ipcDown( touchData.GetTime() );
805           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
806           mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
807
808           if( mVisible == Dali::Window::AUTO )
809           {
810             // Stop hiding indicator
811             ShowIndicator( KEEP_SHOWING );
812           }
813         }
814         break;
815
816         case Dali::PointState::MOTION:
817         {
818           IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
819           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
820         }
821         break;
822
823         case Dali::PointState::UP:
824         case Dali::PointState::INTERRUPTED:
825         {
826           IpcDataEvMouseUp ipcUp( touchData.GetTime() );
827           mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
828
829           if( mVisible == Dali::Window::AUTO )
830           {
831             // Hide indicator
832             ShowIndicator( 0.5f /* hide after 0.5 sec */ );
833           }
834         }
835         break;
836
837         case Dali::TouchPoint::Leave:
838         {
839           IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
840           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
841           IpcDataEvMouseUp ipcOut( touchData.GetTime() );
842           mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
843         }
844         break;
845
846         default:
847           break;
848       }
849
850       return true;
851     }
852   }
853
854   return false;
855 }
856
857 bool Indicator::Connect()
858 {
859   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
860
861   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
862
863   bool connected = false;
864
865   mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
866   if( mServerConnection )
867   {
868     connected = mServerConnection->IsConnected();
869     if( ! connected )
870     {
871       delete mServerConnection;
872       mServerConnection = NULL;
873     }
874   }
875
876   if( !connected )
877   {
878     StartReconnectionTimer();
879   }
880   else
881   {
882     mState = CONNECTED;
883   }
884
885   return connected;
886 }
887
888 void Indicator::StartReconnectionTimer()
889 {
890   if( ! mReconnectTimer )
891   {
892     mReconnectTimer = Dali::Timer::New(1000);
893     mConnection.DisconnectAll();
894     mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
895   }
896   mReconnectTimer.Start();
897 }
898
899 bool Indicator::OnReconnectTimer()
900 {
901   bool retry = false;
902
903   if( mState == DISCONNECTED )
904   {
905     if( !Connect() )
906     {
907       retry = true;
908     }
909   }
910
911   return retry;
912 }
913
914 void Indicator::Disconnect()
915 {
916   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
917
918   mState = DISCONNECTED;
919
920   delete mServerConnection;
921   mServerConnection = NULL;
922
923   ClearSharedFileInfo();
924 }
925
926 void Indicator::Resize( int width, int height )
927 {
928   if( width < 1 )
929   {
930     width = 1;
931   }
932   if( height < 1 )
933   {
934     height = 1;
935   }
936
937   if( mImageWidth != width || mImageHeight != height )
938   {
939     mImageWidth = width;
940     mImageHeight = height;
941
942     mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
943     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
944     mEventActor.SetSize(mImageWidth, mImageHeight);
945     UpdateTopMargin();
946   }
947 }
948
949 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
950 {
951   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
952
953   // epcEvent->ref == w
954   // epcEvent->ref_to == h
955   // epcEvent->response == buffer num
956   // epcEvent->data = lockfile + nul byte
957
958   if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
959       (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
960   {
961     int n = epcEvent->response;
962
963     if( n >= 0 && n < SHARED_FILE_NUMBER )
964     {
965       mCurrentSharedFile = n;
966
967       mSharedFileInfo[n].mImageWidth  = epcEvent->ref;
968       mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
969
970       mSharedFileInfo[n].mLockFileName.clear();
971
972       mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
973
974       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
975                      n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
976     }
977   }
978 }
979
980 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
981 {
982   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
983
984   // epcEvent->ref == shm id
985   // epcEvent->ref_to == shm num
986   // epcEvent->response == buffer num
987   // epcEvent->data = shm ref string + nul byte
988
989   if ( (epcEvent->data) &&
990        (epcEvent->size > 0) &&
991        (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
992   {
993     int n = epcEvent->response;
994
995     if( n >= 0 && n < SHARED_FILE_NUMBER )
996     {
997       mCurrentSharedFile = n;
998
999       mSharedFileInfo[n].mSharedFileName.clear();
1000
1001       mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
1002
1003       mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
1004       mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
1005
1006       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
1007                      n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
1008     }
1009   }
1010 }
1011
1012 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1013 {
1014   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1015
1016   // epcEvent->ref == alpha
1017   // epcEvent->ref_to == sys
1018   // epcEvent->response == buffer num
1019
1020   if ( mSharedBufferType != BUFFER_TYPE_SHM )
1021   {
1022     return ;
1023   }
1024
1025   int n = epcEvent->response;
1026
1027   if( n >= 0 && n < SHARED_FILE_NUMBER )
1028   {
1029     mCurrentSharedFile = n;
1030
1031     delete mSharedFileInfo[n].mSharedFile;
1032     mSharedFileInfo[n].mSharedFile = NULL;
1033
1034     delete mSharedFileInfo[n].mLock;
1035     mSharedFileInfo[n].mLock = NULL;
1036
1037     std::stringstream sharedFileID;
1038     std::stringstream sharedFileNumber;
1039
1040     sharedFileID << mSharedFileInfo[n].mSharedFileID;
1041     sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
1042
1043     std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1044
1045     DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1046
1047     mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1048     if( mSharedFileInfo[n].mSharedFile != NULL )
1049     {
1050       mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
1051       if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1052       {
1053         DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1054       }
1055
1056       CreateNewImage( n );
1057       UpdateVisibility();
1058     }
1059   }
1060 }
1061
1062 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1063 {
1064   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1065
1066   // epcEvent->ref == pixmap id
1067   // epcEvent->ref_to == type
1068   // epcEvent->response == buffer num
1069
1070   if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
1071   {
1072     mSharedBufferType = (BufferType)(epcEvent->ref_to);
1073
1074     ClearSharedFileInfo();
1075
1076     mPixmap = static_cast<PixmapId>(epcEvent->ref);
1077     DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
1078
1079     CreateNewPixmapImage();
1080     UpdateVisibility();
1081   }
1082 }
1083
1084 void Indicator::UpdateTopMargin()
1085 {
1086   int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1087   if (mTopMargin != newMargin)
1088   {
1089     mTopMargin = newMargin;
1090     mAdaptor->IndicatorSizeChanged( mTopMargin );
1091   }
1092 }
1093
1094 void Indicator::UpdateVisibility()
1095 {
1096   if( CheckVisibleState() )
1097   {
1098     // set default indicator type (enable the quick panel)
1099     OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1100   }
1101   else
1102   {
1103     // set default indicator type (disable the quick panel)
1104     OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1105   }
1106
1107   if( !mIsShowing )
1108   {
1109     mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1110   }
1111
1112   SetVisible(mVisible, true);
1113 }
1114
1115 void Indicator::UpdateImageData( int bufferNumber )
1116 {
1117   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1118
1119   if( mState == CONNECTED && mVisible )
1120   {
1121     if(mPixmap == 0)
1122     {
1123       // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1124       CopyToBuffer( bufferNumber );
1125     }
1126     else
1127     {
1128       if(mIsShowing)
1129       {
1130         mAdaptor->RequestUpdateOnce();
1131       }
1132     }
1133   }
1134 }
1135
1136 bool Indicator::CopyToBuffer( int bufferNumber )
1137 {
1138   bool success = false;
1139
1140   if( mSharedFileInfo[bufferNumber].mLock )
1141   {
1142     Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1143     if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1144     {
1145       // Do nothing here.
1146     }
1147     else if( scopedLock.IsLocked() )
1148     {
1149       unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1150       size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1151
1152       if( mIndicatorBuffer->UpdatePixels( src, size ) )
1153       {
1154         mAdaptor->RequestUpdateOnce();
1155         success = true;
1156       }
1157     }
1158   }
1159
1160   return success;
1161 }
1162
1163 void Indicator::CreateNewPixmapImage()
1164 {
1165   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
1166   Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
1167
1168 #ifdef ENABLE_INDICATOR_IMAGE_SAVING
1169   SaveIndicatorImage( nativeImageSource );
1170 #endif
1171
1172   if( nativeImageSource )
1173   {
1174     Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
1175     SetForegroundImage( texture );
1176     mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1177     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1178     mEventActor.SetSize( mImageWidth, mImageHeight );
1179     UpdateTopMargin();
1180   }
1181   else
1182   {
1183     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1184     Disconnect();
1185     if( mObserver != NULL )
1186     {
1187       mObserver->IndicatorClosed( this );
1188     }
1189     // Don't do connection in this callback - strange things happen!
1190     StartReconnectionTimer();
1191   }
1192 }
1193
1194 void Indicator::CreateNewImage( int bufferNumber )
1195 {
1196   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1197   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1198   bool success = false;
1199
1200   if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1201   {
1202     Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1203     if( texture )
1204     {
1205       SetForegroundImage( texture );
1206       success = true;
1207     }
1208   }
1209
1210   if( !success )
1211   {
1212     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1213     Disconnect();
1214     if( mObserver != NULL )
1215     {
1216       mObserver->IndicatorClosed( this );
1217     }
1218     // Don't do connection in this callback - strange things happen!
1219     StartReconnectionTimer();
1220   }
1221 }
1222
1223 Dali::Geometry Indicator::CreateBackgroundGeometry()
1224 {
1225   switch( mOpacityMode )
1226   {
1227     case Dali::Window::TRANSLUCENT:
1228       if( !mTranslucentGeometry )
1229       {
1230         // Construct 5 interval mesh
1231         // 0  +---+  1
1232         //    | \ |
1233         // 2  +---+  3
1234         //    | \ |
1235         // 4  +---+  5
1236         //    | \ |
1237         // 6  +---+  7
1238         //    | \ |
1239         // 8  +---+  9
1240         //    | \ |
1241         // 10 +---+  11
1242
1243         // Create vertices
1244         struct BackgroundVertex
1245         {
1246           Vector2 mPosition;
1247           float   mAlpha;
1248         };
1249
1250         unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1251         BackgroundVertex vertices[ numVertices ];
1252
1253         float d = -0.5f;
1254         float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1255         BackgroundVertex* currentVertex = vertices;
1256         for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1257         {
1258           currentVertex->mPosition = Vector2( -0.5f, d );
1259           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1260           currentVertex++;
1261
1262           currentVertex->mPosition = Vector2( 0.5f, d );
1263           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1264           currentVertex++;
1265         }
1266
1267         // Create indices
1268         unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1269         unsigned short indices[ numIndices ];
1270
1271         unsigned short* currentIndex = indices;
1272         for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1273         {
1274           *currentIndex++ = (2 * y);
1275           *currentIndex++ = (2 * y) + 3;
1276           *currentIndex++ = (2 * y) + 1;
1277
1278           *currentIndex++ = (2 * y);
1279           *currentIndex++ = (2 * y) + 2;
1280           *currentIndex++ = (2 * y) + 3;
1281         }
1282
1283         Dali::Property::Map vertexFormat;
1284         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1285         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1286         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1287         vertexPropertyBuffer.SetData( vertices, numVertices );
1288
1289         // Create the geometry object
1290         mTranslucentGeometry = Dali::Geometry::New();
1291         mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1292         mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1293       }
1294
1295       return mTranslucentGeometry;
1296     case Dali::Window::OPAQUE:
1297
1298       if( !mSolidGeometry )
1299       {
1300         // Create vertices
1301         struct BackgroundVertex
1302         {
1303           Vector2 mPosition;
1304           float   mAlpha;
1305         };
1306
1307         BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1308                                            { Vector2( -0.5f,  0.5f ), 1.0f }, { Vector2( 0.5f,  0.5f ), 1.0f } };
1309
1310         // Create indices
1311         unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1312
1313         Dali::Property::Map vertexFormat;
1314         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1315         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1316         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1317         vertexPropertyBuffer.SetData( vertices, 4 );
1318
1319
1320         // Create the geometry object
1321         mSolidGeometry = Dali::Geometry::New();
1322         mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1323         mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1324       }
1325
1326       return mSolidGeometry;
1327     case Dali::Window::TRANSPARENT:
1328       break;
1329   }
1330
1331   return Dali::Geometry();
1332 }
1333
1334 void Indicator::SetForegroundImage( Dali::Texture texture )
1335 {
1336   if( !mForegroundRenderer && texture )
1337   {
1338     // Create Shader
1339     Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1340
1341     // Create renderer from geometry and material
1342     Dali::Geometry quad = CreateQuadGeometry();
1343     mForegroundRenderer = Dali::Renderer::New( quad, shader );
1344     // Make sure the foreground stays in front of the background
1345     mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1346
1347     // Set blend function
1348     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB,    Dali::BlendFactor::ONE );
1349     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB,   Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1350     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  Dali::BlendFactor::ONE );
1351     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1352
1353     // Create a texture-set and add to renderer
1354
1355     Dali::TextureSet textureSet = Dali::TextureSet::New();
1356     textureSet.SetTexture( 0u, texture );
1357     mForegroundRenderer.SetTextures( textureSet );
1358
1359     mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1360   }
1361   else if( mForegroundRenderer )
1362   {
1363     Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1364     textureSet.SetTexture( 0u, texture );
1365   }
1366
1367   if( mImageWidth == 0 && mImageHeight == 0  && texture)
1368   {
1369     Resize( texture.GetWidth(), texture.GetHeight() );
1370   }
1371 }
1372
1373 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1374 {
1375   if( mObserver != NULL )
1376   {
1377     mObserver->IndicatorTypeChanged( indicatorType );
1378   }
1379 }
1380
1381 void Indicator::DataReceived( void* event )
1382 {
1383   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1384   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1385
1386   switch( epcEvent->minor )
1387   {
1388     case OP_UPDATE:
1389     {
1390       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1391       if( mIsShowing )
1392       {
1393         mAdaptor->RequestUpdateOnce();
1394       }
1395       break;
1396     }
1397     case OP_UPDATE_DONE:
1398     {
1399       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1400       // epcEvent->response == display buffer #
1401       UpdateImageData( epcEvent->response );
1402       break;
1403     }
1404     case OP_SHM_REF0:
1405     {
1406       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1407       SetSharedImageInfo( epcEvent );
1408       break;
1409     }
1410     case OP_SHM_REF1:
1411     {
1412       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1413       SetLockFileInfo( epcEvent );
1414       break;
1415     }
1416     case OP_SHM_REF2:
1417     {
1418       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1419       LoadSharedImage( epcEvent );
1420       break;
1421     }
1422     case OP_PIXMAP_REF:
1423     {
1424       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1425       LoadPixmapImage( epcEvent );
1426       break;
1427     }
1428     case OP_RESIZE:
1429     {
1430       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1431
1432       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1433       {
1434         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1435         Resize( newSize->w, newSize->h );
1436       }
1437       break;
1438     }
1439     case OP_MSG_PARENT:
1440     {
1441       int msgDomain = epcEvent->ref;
1442       int msgId = epcEvent->ref_to;
1443
1444       void *msgData = NULL;
1445       int msgDataSize = 0;
1446       msgData = epcEvent->data;
1447       msgDataSize = epcEvent->size;
1448
1449       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1450
1451       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1452       {
1453         switch( msgId )
1454         {
1455           case MSG_ID_INDICATOR_TYPE:
1456           {
1457             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1458             Type* indicatorType = static_cast<Type*>( epcEvent->data );
1459             OnIndicatorTypeChanged( *indicatorType );
1460             break;
1461           }
1462
1463           case MSG_ID_INDICATOR_START_ANIMATION:
1464           {
1465             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1466
1467             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1468             {
1469               DALI_LOG_ERROR("Message data is incorrect\n");
1470               break;
1471             }
1472
1473             IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1474
1475             if(!CheckVisibleState())
1476             {
1477               ShowIndicator( animData->duration /* n sec */ );
1478             }
1479             break;
1480           }
1481         }
1482       }
1483       break;
1484     }
1485   }
1486 }
1487
1488 void Indicator::ConnectionClosed()
1489 {
1490   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1491
1492   // Will get this callback if the server connection failed to start up.
1493   delete mServerConnection;
1494   mServerConnection = NULL;
1495   mState = DISCONNECTED;
1496
1497   // Attempt to re-connect
1498   Connect();
1499 }
1500
1501 bool Indicator::CheckVisibleState()
1502 {
1503   if( mOrientation == Dali::Window::LANDSCAPE
1504     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1505     || (mVisible == Dali::Window::INVISIBLE)
1506     || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1507   {
1508     return false;
1509   }
1510
1511   return true;
1512 }
1513
1514 void Indicator::ClearSharedFileInfo()
1515 {
1516   for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1517   {
1518     delete mSharedFileInfo[i].mLock;
1519     mSharedFileInfo[i].mLock = NULL;
1520
1521     delete mSharedFileInfo[i].mSharedFile;
1522     mSharedFileInfo[i].mSharedFile = NULL;
1523
1524     mSharedFileInfo[i].mLockFileName.clear();
1525     mSharedFileInfo[i].mSharedFileName.clear();
1526   }
1527 }
1528
1529 /**
1530  * duration can be this
1531  *
1532  * enum
1533  * {
1534  *  KEEP_SHOWING = -1,
1535  *  HIDE_NOW = 0
1536  * };
1537  */
1538 void Indicator::ShowIndicator(float duration)
1539 {
1540   if( !mIndicatorAnimation )
1541   {
1542     mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1543     mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1544   }
1545
1546   if(mIsShowing && !EqualsZero(duration))
1547   {
1548     // If need to show during showing, do nothing.
1549     // In 2nd phase (below) will update timer
1550   }
1551   else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1552   {
1553     // If need to hide during hiding or hidden already, do nothing
1554   }
1555   else
1556   {
1557     mIndicatorAnimation.Clear();
1558
1559     if( EqualsZero(duration) )
1560     {
1561       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1562
1563       mIsShowing = false;
1564
1565       OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1566     }
1567     else
1568     {
1569       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1570
1571       mIsShowing = true;
1572
1573       OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1574     }
1575
1576     mIndicatorAnimation.Play();
1577     mIsAnimationPlaying = true;
1578   }
1579
1580   if(duration > 0)
1581   {
1582     if(!mShowTimer)
1583     {
1584       mShowTimer = Dali::Timer::New(1000 * duration);
1585       mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1586     }
1587     mShowTimer.SetInterval(1000* duration);
1588     mShowTimer.Start();
1589
1590     if( mVisible == Dali::Window::AUTO )
1591     {
1592       // check the stage touch
1593       Dali::Stage::GetCurrent().TouchSignal().Connect( this, &Indicator::OnStageTouch );
1594     }
1595   }
1596   else
1597   {
1598     if(mShowTimer && mShowTimer.IsRunning())
1599     {
1600       mShowTimer.Stop();
1601     }
1602
1603     if( mVisible == Dali::Window::AUTO )
1604     {
1605       // check the stage touch
1606       Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &Indicator::OnStageTouch );
1607     }
1608   }
1609 }
1610
1611 bool Indicator::OnShowTimer()
1612 {
1613   // after time up, hide indicator
1614   ShowIndicator( HIDE_NOW );
1615
1616   return false;
1617 }
1618
1619 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1620 {
1621   mIsAnimationPlaying = false;
1622   // once animation is finished and indicator is hidden, take it off stage
1623   if( mObserver != NULL )
1624   {
1625     mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1626   }
1627 }
1628
1629 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1630 {
1631   // Nothing to do, but we still want to consume pan
1632 }
1633
1634 void Indicator::OnStageTouch(const Dali::TouchData& touchData)
1635 {
1636   // when stage is touched while indicator is showing temporary, hide it
1637   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1638   {
1639     switch( touchData.GetState(0) )
1640     {
1641       case Dali::PointState::DOWN:
1642       {
1643         // if touch point is inside the indicator, indicator is not hidden
1644         if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
1645         {
1646           ShowIndicator( HIDE_NOW );
1647         }
1648         break;
1649       }
1650
1651       default:
1652       break;
1653     }
1654   }
1655 }
1656
1657 } // Adaptor
1658 } // Internal
1659 } // Dali