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