Adaptor: Fix Klocwork issues
[platform/core/uifw/dali-adaptor.git] / adaptors / common / indicator-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "indicator-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <Ecore.h>
23 #include <Evas.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30
31 #include <dali/public-api/images/bitmap-image.h>
32 #include <pixmap-image.h>
33 #include <dali/public-api/actors/image-actor.h>
34 #include <dali/public-api/events/touch-event.h>
35 #include <dali/public-api/events/touch-point.h>
36 #include <dali/public-api/common/stage.h>
37 #include <dali/public-api/actors/blending.h>
38 #include <dali/public-api/shader-effects/shader-effect.h>
39
40 #include <dali/integration-api/debug.h>
41
42 // INTERNAL INCLUDES
43 #include <adaptor-impl.h>
44 #include <accessibility-manager-impl.h>
45
46 using Dali::Vector4;
47
48 #if defined(DEBUG_ENABLED)
49 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
50 #endif
51
52 namespace
53 {
54
55 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
56 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
57 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
58
59 enum
60 {
61   KEEP_SHOWING = -1,
62   HIDE_NOW = 0
63 };
64
65 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
66 const Dali::Vector4 GRADIENT_COLORS[NUM_GRADIENT_INTERVALS+1] =
67 {
68   Vector4(0.0f, 0.0f, 0.0f, 0.6f),
69   Vector4(0.0f, 0.0f, 0.0f, 0.38f),
70   Vector4(0.0f, 0.0f, 0.0f, 0.20f),
71   Vector4(0.0f, 0.0f, 0.0f, 0.08f),
72   Vector4(0.0f, 0.0f, 0.0f, 0.0f),
73   Vector4(0.0f, 0.0f, 0.0f, 0.0f),
74 };
75
76 const float OPAQUE_THRESHOLD(0.99f);
77 const float TRANSPARENT_THRESHOLD(0.05f);
78
79 // Indicator orientation
80 const char* ELM_INDICATOR_PORTRAIT("elm_indicator_portrait");
81 const char* ELM_INDICATOR_LANDSCAPE("elm_indicator_landscape");
82 const char* ELM_INDICATOR_PORTRAIT_FIXED_COLOR_STYLE("elm_indicator_portrait_fixed");
83 const char* ELM_INDICATOR_LANDSCAPE_FIXED_COLOR_STYLE("elm_indicator_landscape_fixed");
84
85 const char* MESH_VERTEX_SHADER =
86 "attribute lowp vec3     aColor;\n"
87 "varying   mediump vec4  vColor;\n"
88 "void main()\n"
89 "{\n"
90 "  gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n"
91 "  vColor = vec4(aColor.r, aColor.g, aColor.b, aTexCoord.x);\n"
92 "}\n";
93
94 const char* MESH_FRAGMENT_SHADER =
95 "varying mediump vec4  vColor;\n"
96 "void main()\n"
97 "{\n"
98 "  gl_FragColor = vColor*uColor;\n"
99 "}\n";
100
101 // Copied from elm_win.h
102
103 /**
104  * Defines the type modes of indicator that can be shown
105  * If the indicator can support several type of indicator,
106  * you can use this enum value to deal with different type of indicator
107  */
108 typedef enum
109 {
110    ELM_WIN_INDICATOR_TYPE_UNKNOWN, /**< Unknown indicator type mode */
111    ELM_WIN_INDICATOR_TYPE_1, /**< Type 0 the the indicator */
112    ELM_WIN_INDICATOR_TYPE_2, /**< Type 1 the indicator */
113 } Elm_Win_Indicator_Type_Mode;
114
115 // Copied from ecore_evas_extn.c
116
117 enum // opcodes
118 {
119   OP_RESIZE,
120   OP_SHOW,
121   OP_HIDE,
122   OP_FOCUS,
123   OP_UNFOCUS,
124   OP_UPDATE,
125   OP_UPDATE_DONE,
126   OP_LOCK_FILE,
127   OP_SHM_REF,
128   OP_EV_MOUSE_IN,
129   OP_EV_MOUSE_OUT,
130   OP_EV_MOUSE_UP,
131   OP_EV_MOUSE_DOWN,
132   OP_EV_MOUSE_MOVE,
133   OP_EV_MOUSE_WHEEL,
134   OP_EV_MULTI_UP,
135   OP_EV_MULTI_DOWN,
136   OP_EV_MULTI_MOVE,
137   OP_EV_KEY_UP,
138   OP_EV_KEY_DOWN,
139   OP_EV_HOLD,
140   OP_MSG_PARENT,
141   OP_MSG,
142   OP_PIXMAP_REF
143 };
144
145 // Copied from elm_conform.c
146
147 const int MSG_DOMAIN_CONTROL_INDICATOR(0x10001);
148 const int MSG_ID_INDICATOR_REPEAT_EVENT(0x10002);
149 const int MSG_ID_INDICATOR_ROTATION(0x10003);
150 const int MSG_ID_INDICATOR_OPACITY(0X1004);
151 const int MSG_ID_INDICATOR_TYPE(0X1005);
152 const int MSG_ID_INDICATOR_START_ANIMATION(0X10006);
153
154 struct IpcDataUpdate
155 {
156    int x, w, y, h;
157 };
158
159 struct IpcDataResize
160 {
161   int w, h;
162 };
163
164 struct IpcIndicatorDataAnimation
165 {
166   unsigned int xwin;
167   double       duration;
168 };
169
170 struct IpcDataEvMouseUp
171 {
172   int               b;
173   Evas_Button_Flags flags;
174   int               mask;
175   unsigned int      timestamp;
176   Evas_Event_Flags  event_flags;
177
178   IpcDataEvMouseUp(unsigned long timestamp)
179   : b(1),
180     flags(EVAS_BUTTON_NONE),
181     mask(0),
182     timestamp(static_cast<unsigned int>(timestamp)),
183     event_flags(EVAS_EVENT_FLAG_NONE)
184   {
185   }
186 };
187
188 struct IpcDataEvMouseDown
189 {
190   int                b;
191   Evas_Button_Flags  flags;
192   int                mask;
193   unsigned int       timestamp;
194   Evas_Event_Flags   event_flags;
195
196   IpcDataEvMouseDown(unsigned long timestamp)
197   : b(1),
198     flags(EVAS_BUTTON_NONE),
199     mask(0),
200     timestamp(static_cast<unsigned int>(timestamp)),
201     event_flags(EVAS_EVENT_FLAG_NONE)
202   {
203   }
204 };
205
206 struct IpcDataEvMouseMove
207 {
208   int                x, y;
209   Evas_Button_Flags  flags;
210   int                mask;
211   unsigned int       timestamp;
212   Evas_Event_Flags   event_flags;
213
214   IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
215   : x(static_cast<Evas_Coord>(touchPoint.local.x)),
216     y(static_cast<Evas_Coord>(touchPoint.local.y)),
217     flags(EVAS_BUTTON_NONE),
218     mask(0),
219     timestamp(static_cast<unsigned int>(timestamp)),
220     event_flags(EVAS_EVENT_FLAG_NONE)
221   {
222   }
223 };
224
225 struct IpcDataEvMouseOut
226 {
227   unsigned int     timestamp;
228   int              mask;
229   Evas_Event_Flags event_flags;
230
231   IpcDataEvMouseOut(unsigned long timestamp)
232   : timestamp(static_cast<unsigned int>(timestamp)),
233     mask(0),
234     event_flags(EVAS_EVENT_FLAG_NONE)
235   {
236   }
237 };
238
239 void SetMeshDataColors(Dali::AnimatableMesh mesh, const Vector4 (&colors)[NUM_GRADIENT_INTERVALS+1])
240 {
241   for( size_t i=0; i<NUM_GRADIENT_INTERVALS+1; i++ )
242   {
243     int j=i*2;
244     mesh[j].SetColor(colors[i]);
245     mesh[j+1].SetColor(colors[i]);
246     mesh[j].SetTextureCoords(Dali::Vector2(colors[i].a, colors[i].a));
247     mesh[j+1].SetTextureCoords(Dali::Vector2(colors[i].a, colors[i].a));
248   }
249 }
250
251 void SetMeshDataColors(Dali::AnimatableMesh mesh, const Vector4& color)
252 {
253   for( size_t i=0, length=NUM_GRADIENT_INTERVALS+1 ; i<length; i++ )
254   {
255     int j=i*2;
256     mesh[j].SetColor(color);
257     mesh[j+1].SetColor(color);
258     mesh[j].SetTextureCoords(Dali::Vector2(color.a, color.a));
259     mesh[j+1].SetTextureCoords(Dali::Vector2(color.a, color.a));
260   }
261 }
262
263 } // anonymous namespace
264
265
266 namespace Dali
267 {
268 namespace Internal
269 {
270 namespace Adaptor
271 {
272 #if defined(DEBUG_ENABLED)
273 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
274 #endif
275
276
277 Indicator::LockFile::LockFile(const char* filename)
278 : mFilename(filename),
279   mErrorThrown(false)
280 {
281   mFileDescriptor = open(filename, O_RDWR);
282   if( mFileDescriptor == -1 )
283   {
284     mFileDescriptor = 0;
285     mErrorThrown = true;
286     DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
287   }
288 }
289
290 Indicator::LockFile::~LockFile()
291 {
292   // Closing file descriptor also unlocks file.
293   close( mFileDescriptor );
294 }
295
296 bool Indicator::LockFile::Lock()
297 {
298   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
299
300   bool locked = false;
301   if( mFileDescriptor > 0 )
302   {
303     if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
304     {
305       locked = true;
306     }
307     else
308     {
309       if( errno == EBADF )
310       {
311         // file descriptor is no longer valid or not writable
312         mFileDescriptor = 0;
313         mErrorThrown = true;
314         DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
315       }
316     }
317   }
318
319   return locked;
320 }
321
322 void Indicator::LockFile::Unlock()
323 {
324   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
325   if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
326   {
327     if( errno == EBADF )
328     {
329       // file descriptor is no longer valid or not writable
330       mFileDescriptor = 0;
331       mErrorThrown = true;
332       DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
333     }
334   }
335 }
336
337 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
338 {
339   bool error = mErrorThrown;
340   mErrorThrown = false;
341   return error;
342 }
343
344 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
345 : mLockFile(lockFile),
346   mLocked(false)
347 {
348   if(mLockFile)
349   {
350     mLocked = mLockFile->Lock();
351   }
352 }
353
354 Indicator::ScopedLock::~ScopedLock()
355 {
356   if( mLockFile )
357   {
358     mLockFile->Unlock();
359   }
360 }
361
362 bool Indicator::ScopedLock::IsLocked()
363 {
364   return mLocked;
365 }
366
367 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, Dali::Window::IndicatorStyle style, Observer* observer )
368 : mPixmap( 0 ),
369   mGestureDetected( false ),
370   mConnection( this ),
371   mStyle( style ),
372   mOpacityMode( Dali::Window::OPAQUE ),
373   mState( DISCONNECTED ),
374   mAdaptor(adaptor),
375   mServerConnection( NULL ),
376   mLock( NULL ),
377   mSharedFile( NULL ),
378   mObserver( observer ),
379   mOrientation( orientation ),
380   mRotation( 0 ),
381   mImageWidth( 0 ),
382   mImageHeight( 0 ),
383   mVisible( Dali::Window::VISIBLE ),
384   mIsShowing( true ),
385   mIsAnimationPlaying( false )
386 {
387   mIndicatorImageActor = Dali::ImageActor::New();
388   mIndicatorImageActor.SetBlendFunc( Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE_MINUS_SRC_ALPHA,
389                                     Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE );
390
391   mIndicatorImageActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
392   mIndicatorImageActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
393
394   // Indicator image handles the touch event including "leave"
395   mIndicatorImageActor.SetLeaveRequired( true );
396   mIndicatorImageActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
397
398   SetBackground();
399   mBackgroundActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
400   mBackgroundActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
401   mBackgroundActor.SetZ( -0.02f );
402
403   // add background to image actor to move it with indicator image
404   mIndicatorImageActor.Add( mBackgroundActor );
405
406   mIndicatorActor = Dali::Actor::New();
407   mIndicatorActor.Add( mIndicatorImageActor );
408
409   if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
410   {
411     mBackgroundActor.SetVisible( false );
412   }
413
414   // Event handler to find out flick down gesture
415   mEventActor = Dali::Actor::New();
416   mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
417   mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
418   mEventActor.SetZ( -0.01f );
419   mIndicatorActor.Add( mEventActor );
420
421   // Attach pan gesture to find flick down during hiding.
422   // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
423   // since it consumes the pan gesture in advance.
424   mPanDetector = Dali::PanGestureDetector::New();
425   mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
426   mPanDetector.Attach( mEventActor );
427
428   Open( orientation );
429
430   // register indicator to accessibility manager
431   Dali::AccessibilityManager accessibilityManager = AccessibilityManager::Get();
432   if(accessibilityManager)
433   {
434     AccessibilityManager::GetImplementation( accessibilityManager ).SetIndicator( this );
435   }
436 }
437
438 Indicator::~Indicator()
439 {
440   if(mEventActor)
441   {
442     mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
443   }
444   Disconnect();
445 }
446
447 void Indicator::SetAdaptor(Adaptor* adaptor)
448 {
449   mAdaptor = adaptor;
450   mIndicatorBuffer->SetAdaptor( adaptor );
451 }
452
453 Dali::Actor Indicator::GetActor()
454 {
455   return mIndicatorActor;
456 }
457
458 void Indicator::Open( Dali::Window::WindowOrientation orientation )
459 {
460   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
461
462   // Calls from Window should be set up to ensure we are in a
463   // disconnected state before opening a second time.
464   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
465
466   Connect( orientation );
467
468   // Change background visibility depending on orientation
469   if(mOrientation == Dali::Window::PORTRAIT || mOrientation == Dali::Window::PORTRAIT_INVERSE)
470   {
471     mBackgroundActor.SetVisible(true);
472   }
473   else
474   {
475     mBackgroundActor.SetVisible(false);
476   }
477 }
478
479 void Indicator::Close()
480 {
481   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s\n", STATE_DEBUG_STRING(mState) );
482
483   if( mState == CONNECTED )
484   {
485     Disconnect();
486     if( mObserver != NULL )
487     {
488       mObserver->IndicatorClosed( this );
489     }
490   }
491
492   Dali::Image emptyImage;
493   mIndicatorImageActor.SetImage(emptyImage);
494 }
495
496 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
497 {
498   mOpacityMode = mode;
499   SetBackground();
500 }
501
502 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
503 {
504   if ( visibleMode != mVisible || forceUpdate )
505   {
506     // If we were previously hidden, then we should update the image data before we display the indicator
507     if ( mVisible == Dali::Window::INVISIBLE )
508     {
509       UpdateImageData();
510     }
511
512     mVisible = visibleMode;
513
514     if( mIndicatorImageActor.GetImage() )
515     {
516       if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
517       {
518         // hide indicator
519         ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
520       }
521       else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
522       {
523         // show indicator
524         ShowIndicator( KEEP_SHOWING );
525       }
526       else
527       {
528         // hide indicator
529         ShowIndicator( HIDE_NOW );
530       }
531     }
532   }
533 }
534
535 bool Indicator::IsConnected()
536 {
537   return ( mState == CONNECTED );
538 }
539
540 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
541 {
542  if(IsConnected())
543  {
544    return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
545  }
546  else
547  {
548    return false;
549  }
550 }
551
552 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
553 {
554   if( mServerConnection )
555   {
556     const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
557
558     // Send touch event to indicator server when indicator is showing
559     if( CheckVisibleState() || mIsShowing )
560     {
561       switch( touchPoint.state )
562       {
563         case Dali::TouchPoint::Down:
564         {
565           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
566           IpcDataEvMouseDown ipcDown( touchEvent.time );
567           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
568           mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
569
570           if( mVisible == Dali::Window::AUTO )
571           {
572             // Stop hiding indicator
573             ShowIndicator( KEEP_SHOWING );
574           }
575         }
576         break;
577
578         case Dali::TouchPoint::Motion:
579         {
580           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
581           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
582         }
583         break;
584
585         case Dali::TouchPoint::Up:
586         {
587           IpcDataEvMouseUp ipcUp( touchEvent.time );
588           mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
589
590           if( mVisible == Dali::Window::AUTO )
591           {
592             // Hide indicator
593             ShowIndicator( 0.5f /* hide after 0.5 sec */ );
594           }
595         }
596         break;
597
598         case Dali::TouchPoint::Leave:
599         {
600           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
601           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
602           IpcDataEvMouseUp ipcOut( touchEvent.time );
603           mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
604         }
605         break;
606
607         default:
608           break;
609       }
610
611       return true;
612     }
613   }
614
615   return false;
616 }
617
618 /**
619  * Return the current orientation in degrees
620  * @return value of 0, 90, 180 or 270
621  */
622 int Indicator::OrientationToDegrees( Dali::Window::WindowOrientation orientation )
623 {
624   int degree = 0;
625
626   switch( orientation )
627   {
628     case Dali::Window::PORTRAIT:
629       degree = 0;
630       break;
631     case Dali::Window::PORTRAIT_INVERSE:
632       degree = 180;
633       break;
634     case Dali::Window::LANDSCAPE:
635       degree = 90;
636       break;
637     case Dali::Window::LANDSCAPE_INVERSE:
638       degree = 270;
639       break;
640   }
641   return degree;
642 }
643
644 bool Indicator::Connect( Dali::Window::WindowOrientation orientation )
645 {
646   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
647
648   bool connected = false;
649   mOrientation = orientation;
650   mRotation = OrientationToDegrees(mOrientation);
651
652   switch( orientation )
653   {
654     case Dali::Window::PORTRAIT:
655       if(mStyle == Dali::Window::FIXED_COLOR)
656       {
657         connected = Connect( ELM_INDICATOR_PORTRAIT_FIXED_COLOR_STYLE );
658       }
659       else
660       {
661         connected = Connect( ELM_INDICATOR_PORTRAIT );
662       }
663       break;
664     case Dali::Window::PORTRAIT_INVERSE:
665       if(mStyle == Dali::Window::FIXED_COLOR)
666       {
667         connected = Connect( ELM_INDICATOR_PORTRAIT_FIXED_COLOR_STYLE );
668       }
669       else
670       {
671         connected = Connect( ELM_INDICATOR_PORTRAIT );
672       }
673       break;
674     case Dali::Window::LANDSCAPE:
675       if(mStyle == Dali::Window::FIXED_COLOR)
676       {
677         connected = Connect( ELM_INDICATOR_LANDSCAPE_FIXED_COLOR_STYLE );
678       }
679       else
680       {
681         connected = Connect( ELM_INDICATOR_LANDSCAPE );
682       }
683       break;
684     case Dali::Window::LANDSCAPE_INVERSE:
685       if(mStyle == Dali::Window::FIXED_COLOR)
686       {
687         connected = Connect( ELM_INDICATOR_LANDSCAPE_FIXED_COLOR_STYLE );
688       }
689       else
690       {
691         connected = Connect( ELM_INDICATOR_LANDSCAPE );
692       }
693       break;
694   }
695
696   return connected;
697 }
698
699 bool Indicator::Connect( const char *serviceName )
700 {
701   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
702
703   bool connected = false;
704
705   mServerConnection = new ServerConnection( serviceName, 0, false, this );
706   if( mServerConnection )
707   {
708     connected = mServerConnection->IsConnected();
709     if( ! connected )
710     {
711       delete mServerConnection;
712       mServerConnection = NULL;
713     }
714   }
715
716   if( !connected )
717   {
718     StartReconnectionTimer();
719   }
720   else
721   {
722     mState = CONNECTED;
723   }
724
725   return connected;
726 }
727
728 void Indicator::StartReconnectionTimer()
729 {
730   if( ! mReconnectTimer )
731   {
732     mReconnectTimer = Dali::Timer::New(1000);
733     mConnection.DisconnectAll();
734     mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
735   }
736   mReconnectTimer.Start();
737 }
738
739 bool Indicator::OnReconnectTimer()
740 {
741   bool retry = false;
742
743   if( mState == DISCONNECTED )
744   {
745     if( ! Connect( mOrientation ) )
746     {
747       retry = true;
748     }
749   }
750
751   return retry;
752 }
753
754 void Indicator::Disconnect()
755 {
756   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
757
758   mState = DISCONNECTED;
759
760   delete mLock;
761   mLock = NULL;
762
763   delete mSharedFile;
764   mSharedFile = NULL;
765
766   delete mServerConnection;
767   mServerConnection = NULL;
768 }
769
770 void Indicator::NewLockFile( Ecore_Ipc_Event_Server_Data *epcEvent )
771 {
772   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
773
774   delete mLock;
775   mLock = NULL;
776
777   if ( (epcEvent->data) &&
778        (epcEvent->size > 0) &&
779        (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
780   {
781     const char* lockFile = static_cast< const char* >( epcEvent->data );
782     mLock = new Indicator::LockFile( lockFile );
783     if( mLock->RetrieveAndClearErrorStatus() )
784     {
785       DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", lockFile );
786     }
787   }
788 }
789
790 void Indicator::Resize( int width, int height )
791 {
792   if( width < 1 )
793   {
794     width = 1;
795   }
796   if( height < 1 )
797   {
798     height = 1;
799   }
800
801   if( mImageWidth != width || mImageHeight != height )
802   {
803     mImageWidth = width;
804     mImageHeight = height;
805
806     // We don't currently handle the pixel buffer size being changed. Create a new image instead
807     if( mSharedFile )
808     {
809       CreateNewImage();
810     }
811   }
812 }
813
814 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
815 {
816   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
817
818   // epcEvent->ref == w
819   // epcEvent->ref_to == h
820   // epcEvent->response == alpha
821   // epcEvent->data = pixmap id
822   if( ( epcEvent->data ) &&
823       (epcEvent->size >= (int)sizeof(PixmapId)) )
824   {
825     if( mSharedFile != NULL )
826     {
827       delete mSharedFile;
828       mSharedFile = NULL;
829     }
830
831     if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
832     {
833       mImageWidth  = epcEvent->ref;
834       mImageHeight = epcEvent->ref_to;
835
836       mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
837       CreateNewPixmapImage();
838
839       if( CheckVisibleState() )
840       {
841         // set default indicator type (enable the quick panel)
842         OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
843       }
844       else
845       {
846         // set default indicator type (disable the quick panel)
847         OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
848       }
849
850       SetVisible(mVisible, true);
851     }
852   }
853 }
854
855 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
856 {
857   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
858
859   // epcEvent->ref == w
860   // epcEvent->ref_to == h
861   // epcEvent->response == alpha
862   // epcEvent->data = shm ref string + nul byte
863   if( ( epcEvent->data ) &&
864       ( ( unsigned char * ) epcEvent->data)[ epcEvent->size - 1 ] == 0 )
865   {
866     if( mSharedFile != NULL )
867     {
868       delete mSharedFile;
869       mSharedFile = NULL;
870     }
871
872     if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
873     {
874       mImageWidth  = epcEvent->ref;
875       mImageHeight = epcEvent->ref_to;
876
877       char* sharedFilename = static_cast<char*>(epcEvent->data);
878
879       mSharedFile = SharedFile::New( sharedFilename, mImageWidth * mImageWidth * 4, true );
880       if( mSharedFile != NULL )
881       {
882         CreateNewImage();
883         mEventActor.SetSize(mImageWidth, mImageHeight);
884
885         if( CheckVisibleState() )
886         {
887           // set default indicator type (enable the quick panel)
888           OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
889         }
890         else
891         {
892           // set default indicator type (disable the quick panel)
893           OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
894         }
895
896         SetVisible(mVisible, true);
897       }
898     }
899   }
900 }
901
902 void Indicator::UpdateImageData()
903 {
904   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s\n", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
905
906   if( mState == CONNECTED && mVisible )
907   {
908     if(mPixmap == 0)
909     {
910       // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
911       CopyToBuffer();
912     }
913     else
914     {
915       if(mIsShowing)
916       {
917         mAdaptor->RequestUpdateOnce();
918       }
919     }
920   }
921 }
922
923 bool Indicator::CopyToBuffer()
924 {
925   bool success = false;
926
927   if( mLock )
928   {
929     Indicator::ScopedLock scopedLock(mLock);
930     if( mLock->RetrieveAndClearErrorStatus() )
931     {
932       // Do nothing here.
933     }
934     else if( scopedLock.IsLocked() )
935     {
936       unsigned char *src = mSharedFile->GetAddress();
937       size_t size = mImageWidth * mImageHeight * 4;
938
939       if( mIndicatorBuffer->UpdatePixels( src, size ) )
940       {
941         mAdaptor->RequestUpdateOnce();
942         success = true;
943       }
944     }
945   }
946
947   return success;
948 }
949
950 void Indicator::SetBackground()
951 {
952   if( ! mBackgroundActor )
953   {
954     ConstructBackgroundMesh();
955   }
956
957   switch( mOpacityMode )
958   {
959     case Dali::Window::TRANSLUCENT:
960     {
961       SetMeshDataColors( mBackgroundMesh, GRADIENT_COLORS );
962     }
963     break;
964
965     case Dali::Window::TRANSPARENT:
966     {
967       SetMeshDataColors( mBackgroundMesh, Color::TRANSPARENT );
968     }
969     break;
970
971     case Dali::Window::OPAQUE:
972     default :
973     {
974       SetMeshDataColors( mBackgroundMesh, Color::BLACK );
975     }
976     break;
977   }
978 }
979
980 void Indicator::CreateNewPixmapImage()
981 {
982   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d\n", mImageWidth, mImageHeight );
983   Dali::PixmapImagePtr pixmapImage = Dali::PixmapImage::New(mPixmap, Dali::Adaptor::Get());
984
985   if( pixmapImage )
986   {
987     mIndicatorImageActor.SetImage( Dali::Image::New(*pixmapImage) );
988     mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
989     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
990     mEventActor.SetSize(mImageWidth, mImageHeight);
991
992     SetBackground();
993     if( mBackgroundActor )
994     {
995       mBackgroundActor.SetSize( mImageWidth, mImageHeight );
996     }
997   }
998   else
999   {
1000     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1001     Disconnect();
1002     if( mObserver != NULL )
1003     {
1004       mObserver->IndicatorClosed( this );
1005     }
1006     // Don't do connection in this callback - strange things happen!
1007     StartReconnectionTimer();
1008   }
1009 }
1010
1011 void Indicator::CreateNewImage()
1012 {
1013   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d\n", mImageWidth, mImageHeight );
1014   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mImageWidth, mImageHeight, Pixel::BGRA8888 );
1015   Dali::Image image = Dali::Image::New( mIndicatorBuffer->GetNativeImage() );
1016
1017   if( CopyToBuffer() ) // Only create images if we have valid image buffer
1018   {
1019     mIndicatorImageActor.SetImage( image );
1020     mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
1021     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1022     mEventActor.SetSize(mImageWidth, mImageHeight);
1023
1024     SetBackground();
1025     if( mBackgroundActor )
1026     {
1027       mBackgroundActor.SetSize( mImageWidth, mImageHeight );
1028     }
1029   }
1030   else
1031   {
1032     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1033     Disconnect();
1034     if( mObserver != NULL )
1035     {
1036       mObserver->IndicatorClosed( this );
1037     }
1038     // Don't do connection in this callback - strange things happen!
1039     StartReconnectionTimer();
1040   }
1041 }
1042
1043 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1044 {
1045   if( mObserver != NULL )
1046   {
1047     mObserver->IndicatorTypeChanged( indicatorType );
1048   }
1049 }
1050
1051 void Indicator::DataReceived( void* event )
1052 {
1053   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1054   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1055
1056   switch( epcEvent->minor )
1057   {
1058     case OP_UPDATE:
1059       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1060       if(mPixmap != 0 && mIsShowing)
1061       {
1062         mAdaptor->RequestUpdateOnce();
1063       }
1064       break;
1065
1066     case OP_UPDATE_DONE:
1067       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE\n" );
1068       UpdateImageData();
1069       break;
1070
1071     case OP_LOCK_FILE:
1072       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_LOCK_FILE\n" );
1073       NewLockFile( epcEvent );
1074       break;
1075
1076     case OP_SHM_REF:
1077       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF\n" );
1078       LoadSharedImage( epcEvent );
1079       break;
1080
1081     case OP_PIXMAP_REF:
1082       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1083       LoadPixmapImage( epcEvent );
1084       break;
1085
1086     case OP_RESIZE:
1087       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1088
1089       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1090       {
1091         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1092         Resize( newSize->w, newSize->h );
1093       }
1094       break;
1095
1096     case OP_MSG_PARENT:
1097     {
1098       int msgDomain = epcEvent->ref;
1099       int msgId = epcEvent->ref_to;
1100
1101       void *msgData = NULL;
1102       int msgDataSize = 0;
1103       msgData = epcEvent->data;
1104       msgDataSize = epcEvent->size;
1105
1106       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1107       {
1108         switch( msgId )
1109         {
1110           case MSG_ID_INDICATOR_TYPE:
1111           {
1112             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1113             Type* indicatorType = static_cast<Type*>( epcEvent->data );
1114             OnIndicatorTypeChanged( *indicatorType );
1115             break;
1116           }
1117
1118           case MSG_ID_INDICATOR_START_ANIMATION:
1119           {
1120             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1121             {
1122               DALI_LOG_ERROR("Message data is incorrect");
1123               break;
1124             }
1125
1126             IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1127
1128             if(!CheckVisibleState())
1129             {
1130               ShowIndicator( animData->duration /* n sec */ );
1131             }
1132             break;
1133           }
1134
1135         }
1136       }
1137       break;
1138     }
1139   }
1140 }
1141
1142 void Indicator::ConnectionClosed()
1143 {
1144   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1145
1146   // Will get this callback if the server connection failed to start up.
1147   delete mServerConnection;
1148   mServerConnection = NULL;
1149   mState = DISCONNECTED;
1150
1151   // Attempt to re-connect
1152   Connect(mOrientation);
1153 }
1154
1155 bool Indicator::CheckVisibleState()
1156 {
1157   if( mOrientation == Dali::Window::LANDSCAPE
1158     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1159     || (mVisible != Dali::Window::VISIBLE) )
1160   {
1161     return false;
1162   }
1163
1164   return true;
1165 }
1166
1167 void Indicator::ConstructBackgroundMesh()
1168 {
1169   // Construct 5 interval mesh
1170   // 0  +---+  1
1171   //    | \ |
1172   // 2  +---+  3
1173   //    | \ |
1174   // 4  +---+  5
1175   //    | \ |
1176   // 6  +---+  7
1177   //    | \ |
1178   // 8  +---+  9
1179   //    | \ |
1180   // 10 +---+  11
1181   Dali::AnimatableMesh::Faces faces;
1182   faces.reserve(NUM_GRADIENT_INTERVALS * 6); // 2 tris per interval
1183   for(int i=0; i<NUM_GRADIENT_INTERVALS; i++)
1184   {
1185     int j=i*2;
1186     faces.push_back(j); faces.push_back(j+3); faces.push_back(j+1);
1187     faces.push_back(j); faces.push_back(j+2); faces.push_back(j+3);
1188   }
1189
1190   mBackgroundMesh = Dali::AnimatableMesh::New((NUM_GRADIENT_INTERVALS+1)*2, faces);
1191   float interval=1.0f / (float)NUM_GRADIENT_INTERVALS;
1192   for(int i=0;i<NUM_GRADIENT_INTERVALS+1;i++)
1193   {
1194     int j=i*2;
1195     mBackgroundMesh[j  ].SetPosition(Vector3(-0.5f, -0.5f+(interval*(float)i), 0.0f));
1196     mBackgroundMesh[j+1].SetPosition(Vector3( 0.5f, -0.5f+(interval*(float)i), 0.0f));
1197   }
1198
1199   mBackgroundActor = Dali::MeshActor::New(mBackgroundMesh);
1200   mBackgroundActor.SetAffectedByLighting(false);
1201   Dali::ShaderEffect shaderEffect = Dali::ShaderEffect::New( MESH_VERTEX_SHADER, MESH_FRAGMENT_SHADER,
1202                                                              GEOMETRY_TYPE_MESH, // Using vertex color
1203                                                              Dali::ShaderEffect::HINT_BLENDING );
1204   mBackgroundActor.SetShaderEffect(shaderEffect);
1205 }
1206
1207 /**
1208  * duration can be this
1209  *
1210  * enum
1211  * {
1212  *  KEEP_SHOWING = -1,
1213  *  HIDE_NOW = 0
1214  * };
1215  */
1216 void Indicator::ShowIndicator(float duration)
1217 {
1218   if( !mIndicatorAnimation )
1219   {
1220     mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1221     mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1222   }
1223
1224   if(mIsShowing && !EqualsZero(duration))
1225   {
1226     // If need to show during showing, do nothing.
1227     // In 2nd phase (below) will update timer
1228   }
1229   else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1230   {
1231     // If need to hide during hiding or hidden already, do nothing
1232   }
1233   else
1234   {
1235     if( EqualsZero(duration) )
1236     {
1237       mIndicatorAnimation.MoveTo(mIndicatorImageActor, Vector3(0, -mImageHeight, 0), Dali::AlphaFunctions::EaseOut);
1238
1239       mIsShowing = false;
1240
1241       OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1242     }
1243     else
1244     {
1245       mIndicatorAnimation.MoveTo(mIndicatorImageActor, Vector3(0, 0, 0), Dali::AlphaFunctions::EaseOut);
1246
1247       mIsShowing = true;
1248
1249       OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1250     }
1251
1252     mIndicatorAnimation.Play();
1253     mIsAnimationPlaying = true;
1254   }
1255
1256   if(duration > 0)
1257   {
1258     if(!mShowTimer)
1259     {
1260       mShowTimer = Dali::Timer::New(1000 * duration);
1261       mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1262     }
1263     mShowTimer.SetInterval(1000* duration);
1264     mShowTimer.Start();
1265
1266     if( mVisible == Dali::Window::AUTO )
1267     {
1268         // check the stage touch
1269         Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1270     }
1271   }
1272   else
1273   {
1274     if(mShowTimer && mShowTimer.IsRunning())
1275     {
1276       mShowTimer.Stop();
1277     }
1278
1279     if( mVisible == Dali::Window::AUTO )
1280     {
1281         // check the stage touch
1282         Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1283     }
1284   }
1285 }
1286
1287 bool Indicator::OnShowTimer()
1288 {
1289   // after time up, hide indicator
1290   ShowIndicator( HIDE_NOW );
1291
1292   return false;
1293 }
1294
1295 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1296 {
1297   mIsAnimationPlaying = false;
1298 }
1299
1300 void Indicator::OnPan( Dali::Actor actor, Dali::PanGesture gesture )
1301 {
1302   if( mServerConnection )
1303   {
1304     switch( gesture.state )
1305     {
1306       case Gesture::Started:
1307       {
1308         mGestureDetected = false;
1309
1310         // The gesture position is the current position after it has moved by the displacement.
1311         // We want to reference the original position.
1312         mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1313       }
1314
1315       // No break, Fall through
1316       case Gesture::Continuing:
1317       {
1318         if( mVisible == Dali::Window::AUTO && !mIsShowing )
1319         {
1320           // Only take one touch point
1321           if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1322           {
1323             mGestureDeltaY += gesture.displacement.y;
1324
1325             if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1326             {
1327               ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1328               mGestureDetected = true;
1329             }
1330           }
1331         }
1332
1333         break;
1334       }
1335
1336       case Gesture::Finished:
1337       case Gesture::Cancelled:
1338       {
1339         // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1340         if( mVisible == Dali::Window::AUTO && mIsShowing )
1341         {
1342           ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1343         }
1344         break;
1345       }
1346
1347
1348       default:
1349         break;
1350     }
1351   }
1352 }
1353
1354 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1355 {
1356   const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1357
1358   // when stage is touched while indicator is showing temporary, hide it
1359   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1360   {
1361     switch( touchPoint.state )
1362     {
1363       case Dali::TouchPoint::Down:
1364       {
1365         ShowIndicator( HIDE_NOW );
1366         break;
1367       }
1368
1369       default:
1370       break;
1371     }
1372   }
1373 }
1374
1375 } // Adaptor
1376 } // Internal
1377 } // Dali