aaf634d1446dd0ad3dc31f63e4c32dbac3cf4886
[platform/core/uifw/dali-adaptor.git] / adaptors / tizen / internal / common / indicator-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include "indicator-impl.h"
19
20 // EXTERNAL INCLUDES
21 #include <Ecore.h>
22 #include <Evas.h>
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29
30 #include <dali/public-api/images/bitmap-image.h>
31 #include <dali/public-api/actors/image-actor.h>
32 #include <dali/public-api/events/touch-event.h>
33 #include <dali/public-api/events/touch-point.h>
34 #include <dali/public-api/common/stage.h>
35 #include <dali/public-api/actors/blending.h>
36 #include <dali/public-api/shader-effects/shader-effect.h>
37
38 #include <dali/integration-api/debug.h>
39
40 // INTERNAL INCLUDES
41 #include <internal/common/adaptor-impl.h>
42 #include <internal/common/accessibility-manager-impl.h>
43
44 using Dali::Vector4;
45
46 #if defined(DEBUG_ENABLED)
47 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
48 #endif
49
50 namespace
51 {
52 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
53 const Dali::Vector4 GRADIENT_COLORS[NUM_GRADIENT_INTERVALS+1] =
54 {
55   Vector4(0.0f, 0.0f, 0.0f, 0.6f),
56   Vector4(0.0f, 0.0f, 0.0f, 0.38f),
57   Vector4(0.0f, 0.0f, 0.0f, 0.20f),
58   Vector4(0.0f, 0.0f, 0.0f, 0.08f),
59   Vector4(0.0f, 0.0f, 0.0f, 0.0f),
60   Vector4(0.0f, 0.0f, 0.0f, 0.0f),
61 };
62
63 const float OPAQUE_THRESHOLD(0.99f);
64 const float TRANSPARENT_THRESHOLD(0.05f);
65
66 // Indicator orientation
67 const char* ELM_INDICATOR_PORTRAIT("elm_indicator_portrait");
68 const char* ELM_INDICATOR_LANDSCAPE("elm_indicator_landscape");
69
70 const char* MESH_VERTEX_SHADER =
71 "attribute lowp vec3     aColor;\n"
72 "varying   mediump vec4  vColor;\n"
73 "void main()\n"
74 "{\n"
75 "  gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n"
76 "  vColor = vec4(aColor.r, aColor.g, aColor.b, aTexCoord.x);\n"
77 "}\n";
78
79 const char* MESH_FRAGMENT_SHADER =
80 "varying mediump vec4  vColor;\n"
81 "void main()\n"
82 "{\n"
83 "  gl_FragColor = vColor*uColor;\n"
84 "}\n";
85
86 // Copied from elm_win.h
87
88 /**
89  * Defines the opacity modes of indicator that can be shown
90  */
91 typedef enum
92 {
93    ELM_WIN_INDICATOR_OPACITY_UNKNOWN, /**< Unknown indicator opacity mode */
94    ELM_WIN_INDICATOR_OPAQUE,          /**< Opacifies the indicator */
95    ELM_WIN_INDICATOR_TRANSLUCENT,     /**< Be translucent the indicator */
96    ELM_WIN_INDICATOR_TRANSPARENT      /**< Transparentizes the indicator */
97 } Elm_Win_Indicator_Opacity_Mode;
98
99 /**
100  * Defines the type modes of indicator that can be shown
101  * If the indicator can support several type of indicator,
102  * you can use this enum value to deal with different type of indicator
103  */
104 typedef enum
105 {
106    ELM_WIN_INDICATOR_TYPE_UNKNOWN, /**< Unknown indicator type mode */
107    ELM_WIN_INDICATOR_TYPE_1, /**< Type 0 the the indicator */
108    ELM_WIN_INDICATOR_TYPE_2, /**< Type 1 the indicator */
109 } Elm_Win_Indicator_Type_Mode;
110
111 // Copied from ecore_evas_extn.c
112
113 enum // opcodes
114 {
115   OP_RESIZE,
116   OP_SHOW,
117   OP_HIDE,
118   OP_FOCUS,
119   OP_UNFOCUS,
120   OP_UPDATE,
121   OP_UPDATE_DONE,
122   OP_LOCK_FILE,
123   OP_SHM_REF,
124   OP_EV_MOUSE_IN,
125   OP_EV_MOUSE_OUT,
126   OP_EV_MOUSE_UP,
127   OP_EV_MOUSE_DOWN,
128   OP_EV_MOUSE_MOVE,
129   OP_EV_MOUSE_WHEEL,
130   OP_EV_MULTI_UP,
131   OP_EV_MULTI_DOWN,
132   OP_EV_MULTI_MOVE,
133   OP_EV_KEY_UP,
134   OP_EV_KEY_DOWN,
135   OP_EV_HOLD,
136   OP_MSG_PARENT,
137   OP_MSG
138 };
139
140 // Copied from elm_conform.c
141
142 const int MSG_DOMAIN_CONTROL_INDICATOR(0x10001);
143 const int MSG_ID_INDICATOR_REPEAT_EVENT(0x10002);
144 const int MSG_ID_INDICATOR_ROTATION(0x10003);
145 const int MSG_ID_INDICATOR_OPACITY(0X1004);
146 const int MSG_ID_INDICATOR_TYPE(0X1005);
147
148
149 struct IpcDataUpdate
150 {
151    int x, w, y, h;
152 };
153
154 struct IpcDataResize
155 {
156   int w, h;
157 };
158
159 struct IpcDataEvMouseUp
160 {
161   int               b;
162   Evas_Button_Flags flags;
163   int               mask;
164   unsigned int      timestamp;
165   Evas_Event_Flags  event_flags;
166
167   IpcDataEvMouseUp(unsigned long timestamp)
168   : b(1),
169     flags(EVAS_BUTTON_NONE),
170     mask(0),
171     timestamp(static_cast<unsigned int>(timestamp)),
172     event_flags(EVAS_EVENT_FLAG_NONE)
173   {
174   }
175 };
176
177 struct IpcDataEvMouseDown
178 {
179   int                b;
180   Evas_Button_Flags  flags;
181   int                mask;
182   unsigned int       timestamp;
183   Evas_Event_Flags   event_flags;
184
185   IpcDataEvMouseDown(unsigned long timestamp)
186   : b(1),
187     flags(EVAS_BUTTON_NONE),
188     mask(0),
189     timestamp(static_cast<unsigned int>(timestamp)),
190     event_flags(EVAS_EVENT_FLAG_NONE)
191   {
192   }
193 };
194
195 struct IpcDataEvMouseMove
196 {
197   int                x, y;
198   Evas_Button_Flags  flags;
199   int                mask;
200   unsigned int       timestamp;
201   Evas_Event_Flags   event_flags;
202
203   IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
204   : x(static_cast<Evas_Coord>(touchPoint.local.x)),
205     y(static_cast<Evas_Coord>(touchPoint.local.y)),
206     flags(EVAS_BUTTON_NONE),
207     mask(0),
208     timestamp(static_cast<unsigned int>(timestamp)),
209     event_flags(EVAS_EVENT_FLAG_NONE)
210   {
211   }
212 };
213
214 struct IpcDataEvMouseOut
215 {
216   unsigned int     timestamp;
217   int              mask;
218   Evas_Event_Flags event_flags;
219
220   IpcDataEvMouseOut(unsigned long timestamp)
221   : timestamp(static_cast<unsigned int>(timestamp)),
222     mask(0),
223     event_flags(EVAS_EVENT_FLAG_NONE)
224   {
225   }
226 };
227
228 void SetMeshDataColors(Dali::AnimatableMesh mesh, const Vector4 (&colors)[NUM_GRADIENT_INTERVALS+1])
229 {
230   for( size_t i=0; i<NUM_GRADIENT_INTERVALS+1; i++ )
231   {
232     int j=i*2;
233     mesh[j].SetColor(colors[i]);
234     mesh[j+1].SetColor(colors[i]);
235     mesh[j].SetTextureCoords(Dali::Vector2(colors[i].a, colors[i].a));
236     mesh[j+1].SetTextureCoords(Dali::Vector2(colors[i].a, colors[i].a));
237   }
238 }
239
240 void SetMeshDataColors(Dali::AnimatableMesh mesh, const Vector4& color)
241 {
242   for( size_t i=0, length=NUM_GRADIENT_INTERVALS+1 ; i<length; i++ )
243   {
244     int j=i*2;
245     mesh[j].SetColor(color);
246     mesh[j+1].SetColor(color);
247     mesh[j].SetTextureCoords(Dali::Vector2(color.a, color.a));
248     mesh[j+1].SetTextureCoords(Dali::Vector2(color.a, color.a));
249   }
250 }
251
252 } // anonymous namespace
253
254
255 namespace Dali
256 {
257 namespace Internal
258 {
259 namespace Adaptor
260 {
261 #if defined(DEBUG_ENABLED)
262 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
263 #endif
264
265
266 Indicator::LockFile::LockFile(const char* filename)
267 : mFilename(filename),
268   mErrorThrown(false)
269 {
270   mFileDescriptor = open(filename, O_RDWR);
271   if( mFileDescriptor == -1 )
272   {
273     mFileDescriptor = 0;
274     mErrorThrown = true;
275     DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
276   }
277 }
278
279 Indicator::LockFile::~LockFile()
280 {
281   // Closing file descriptor also unlocks file.
282   close( mFileDescriptor );
283 }
284
285 bool Indicator::LockFile::Lock()
286 {
287   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
288
289   bool locked = false;
290   if( mFileDescriptor > 0 )
291   {
292     if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
293     {
294       locked = true;
295     }
296     else
297     {
298       if( errno == EBADF )
299       {
300         // file descriptor is no longer valid or not writable
301         mFileDescriptor = 0;
302         mErrorThrown = true;
303         DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
304       }
305     }
306   }
307
308   return locked;
309 }
310
311 void Indicator::LockFile::Unlock()
312 {
313   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
314   if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
315   {
316     if( errno == EBADF )
317     {
318       // file descriptor is no longer valid or not writable
319       mFileDescriptor = 0;
320       mErrorThrown = true;
321       DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
322     }
323   }
324 }
325
326 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
327 {
328   bool error = mErrorThrown;
329   mErrorThrown = false;
330   return error;
331 }
332
333 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
334 : mLockFile(lockFile),
335   mLocked(false)
336 {
337   if(mLockFile)
338   {
339     mLocked = mLockFile->Lock();
340   }
341 }
342
343 Indicator::ScopedLock::~ScopedLock()
344 {
345   if( mLockFile )
346   {
347     mLockFile->Unlock();
348   }
349 }
350
351 bool Indicator::ScopedLock::IsLocked()
352 {
353   return mLocked;
354 }
355
356 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, Observer* observer )
357 : mConnection( this ),
358   mOpacityMode( Dali::Window::OPAQUE ),
359   mState( DISCONNECTED ),
360   mAdaptor(adaptor),
361   mServerConnection( NULL ),
362   mLock( NULL ),
363   mSharedFile( NULL ),
364   mObserver( observer ),
365   mOrientation( orientation ),
366   mRotation( 0 ),
367   mImageWidth( 0 ),
368   mImageHeight( 0 ),
369   mVisible( false )
370 {
371   mIndicatorImageActor = Dali::ImageActor::New();
372   mIndicatorImageActor.SetLeaveRequired(true);
373   mIndicatorImageActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
374   mIndicatorImageActor.SetBlendFunc(Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE_MINUS_SRC_ALPHA,
375                                     Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE );
376   mIndicatorImageActor.SetPositionInheritanceMode(USE_PARENT_POSITION);
377
378   SetBackground();
379   mBackgroundActor.SetPositionInheritanceMode(USE_PARENT_POSITION);
380
381   mIndicatorActor = Dali::Actor::New();
382   mIndicatorActor.SetParentOrigin( ParentOrigin::CENTER );
383   mIndicatorActor.SetAnchorPoint(  AnchorPoint::CENTER );
384   mIndicatorActor.Add(mBackgroundActor);
385   mIndicatorActor.Add(mIndicatorImageActor);
386
387   if(mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE)
388   {
389     mBackgroundActor.SetVisible(false);
390   }
391
392   Open( orientation );
393
394   Dali::AccessibilityManager accessibilityManager = AccessibilityManager::Get();
395   if(accessibilityManager)
396   {
397     AccessibilityManager::GetImplementation( accessibilityManager ).SetIndicator(this);
398   }
399 }
400
401 Indicator::~Indicator()
402 {
403   if(mIndicatorImageActor)
404   {
405     mIndicatorImageActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
406   }
407   Disconnect();
408 }
409
410 void Indicator::SetAdaptor(Adaptor* adaptor)
411 {
412   mAdaptor = adaptor;
413   mIndicatorBuffer->SetAdaptor( adaptor );
414 }
415
416 Dali::Actor Indicator::GetActor()
417 {
418   return mIndicatorActor;
419 }
420
421 void Indicator::Open( Dali::Window::WindowOrientation orientation )
422 {
423   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
424
425   // Calls from Window should be set up to ensure we are in a
426   // disconnected state before opening a second time.
427   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
428
429   Connect( orientation );
430
431   // Change background visibility depending on orientation
432   if(mOrientation == Dali::Window::PORTRAIT || mOrientation == Dali::Window::PORTRAIT_INVERSE)
433   {
434     mBackgroundActor.SetVisible(true);
435   }
436   else
437   {
438     mBackgroundActor.SetVisible(false);
439   }
440 }
441
442 void Indicator::Close()
443 {
444   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s\n", STATE_DEBUG_STRING(mState) );
445
446   if( mState == CONNECTED )
447   {
448     Disconnect();
449     if( mObserver != NULL )
450     {
451       mObserver->IndicatorClosed( this );
452     }
453   }
454
455   Dali::Image emptyImage;
456   mIndicatorImageActor.SetImage(emptyImage);
457 }
458
459 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode, bool notifyService )
460 {
461   if( mOpacityMode != mode || notifyService )
462   {
463     // notify opacity mode to indicator service
464     SendOpacityMode(mode);
465   }
466
467   mOpacityMode = mode;
468   SetBackground();
469 }
470
471 void Indicator::SetVisible( bool visibility )
472 {
473   if ( visibility != mVisible )
474   {
475     mVisible = visibility;
476
477     // If we were previously hidden, then we should update the image data before we display the indicator
478     if ( mVisible )
479     {
480       UpdateImageData();
481     }
482   }
483 }
484
485 bool Indicator::IsConnected()
486 {
487   return ( mState == CONNECTED );
488 }
489
490 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
491 {
492  if(IsConnected())
493  {
494    return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
495  }
496  else
497  {
498    return false;
499  }
500 }
501
502 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
503 {
504   if(mServerConnection)
505   {
506     const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
507
508     switch( touchPoint.state )
509     {
510       case Dali::TouchPoint::Down:
511       {
512         IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
513         IpcDataEvMouseDown ipcDown( touchEvent.time );
514         mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
515         mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
516       }
517       break;
518
519       case Dali::TouchPoint::Motion:
520       {
521         IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
522         mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
523       }
524       break;
525
526       case Dali::TouchPoint::Up:
527       {
528         IpcDataEvMouseUp ipcUp( touchEvent.time );
529         mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
530       }
531       break;
532
533       case Dali::TouchPoint::Leave:
534       {
535         IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
536         mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
537         IpcDataEvMouseUp ipcOut( touchEvent.time );
538         mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
539       }
540       break;
541
542       default:
543         break;
544     }
545   }
546   return true;
547 }
548
549 /**
550  * Return the current orientation in degrees
551  * @return value of 0, 90, 180 or 270
552  */
553 int Indicator::OrientationToDegrees( Dali::Window::WindowOrientation orientation )
554 {
555   int degree = 0;
556
557   switch( orientation )
558   {
559     case Dali::Window::PORTRAIT:
560       degree = 0;
561       break;
562     case Dali::Window::PORTRAIT_INVERSE:
563       degree = 180;
564       break;
565     case Dali::Window::LANDSCAPE:
566       degree = 90;
567       break;
568     case Dali::Window::LANDSCAPE_INVERSE:
569       degree = 270;
570       break;
571   }
572   return degree;
573 }
574
575 void Indicator::SendOpacityMode( Dali::Window::IndicatorBgOpacity mode )
576 {
577   Elm_Win_Indicator_Opacity_Mode windowIndicatorMode;
578   switch(mode)
579   {
580     case Dali::Window::OPAQUE:
581       windowIndicatorMode = ELM_WIN_INDICATOR_OPAQUE;
582       break;
583     case Dali::Window::TRANSPARENT:
584       windowIndicatorMode = ELM_WIN_INDICATOR_TRANSPARENT;
585       break;
586     case Dali::Window::TRANSLUCENT:
587       windowIndicatorMode = ELM_WIN_INDICATOR_TRANSLUCENT;
588       break;
589   }
590
591   if( mServerConnection )
592   {
593     mServerConnection->SendEvent( OP_MSG,
594                                   MSG_DOMAIN_CONTROL_INDICATOR,
595                                   MSG_ID_INDICATOR_OPACITY,
596                                   &windowIndicatorMode, sizeof( Elm_Win_Indicator_Opacity_Mode ) );
597   }
598 }
599
600
601 bool Indicator::Connect( Dali::Window::WindowOrientation orientation )
602 {
603   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
604
605   bool connected = false;
606   mOrientation = orientation;
607   mRotation = OrientationToDegrees(mOrientation);
608
609   switch( orientation )
610   {
611     case Dali::Window::PORTRAIT:
612       connected = Connect( ELM_INDICATOR_PORTRAIT );
613       break;
614     case Dali::Window::PORTRAIT_INVERSE:
615       connected = Connect( ELM_INDICATOR_PORTRAIT );
616       break;
617     case Dali::Window::LANDSCAPE:
618       connected = Connect( ELM_INDICATOR_LANDSCAPE );
619       break;
620     case Dali::Window::LANDSCAPE_INVERSE:
621       connected = Connect( ELM_INDICATOR_LANDSCAPE );
622       break;
623   }
624
625   return connected;
626 }
627
628 bool Indicator::Connect( const char *serviceName )
629 {
630   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
631
632   bool connected = false;
633
634   mServerConnection = new ServerConnection( serviceName, 0, false, this );
635   if( mServerConnection )
636   {
637     connected = mServerConnection->IsConnected();
638     if( ! connected )
639     {
640       delete mServerConnection;
641       mServerConnection = NULL;
642     }
643   }
644
645   if( connected )
646   {
647     mState = CONNECTED;
648     int domain = MSG_DOMAIN_CONTROL_INDICATOR;
649     int refTo = MSG_ID_INDICATOR_ROTATION;
650     mServerConnection->SendEvent( OP_MSG, domain, refTo, &mRotation, sizeof(int) );
651   }
652   else
653   {
654     StartReconnectionTimer();
655   }
656
657   return connected;
658 }
659
660 void Indicator::StartReconnectionTimer()
661 {
662   if( ! mReconnectTimer )
663   {
664     mReconnectTimer = Dali::Timer::New(1000);
665     mConnection.DisconnectAll();
666     mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
667   }
668   mReconnectTimer.Start();
669 }
670
671 bool Indicator::OnReconnectTimer()
672 {
673   bool retry = false;
674
675   if( mState == DISCONNECTED )
676   {
677     if( ! Connect( mOrientation ) )
678     {
679       retry = true;
680     }
681   }
682
683   return retry;
684 }
685
686 void Indicator::Disconnect()
687 {
688   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
689
690   mState = DISCONNECTED;
691
692   delete mLock;
693   mLock = NULL;
694
695   delete mSharedFile;
696   mSharedFile = NULL;
697
698   delete mServerConnection;
699   mServerConnection = NULL;
700 }
701
702 void Indicator::NewLockFile( Ecore_Ipc_Event_Server_Data *epcEvent )
703 {
704   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
705
706   delete mLock;
707   mLock = NULL;
708
709   if ( (epcEvent->data) &&
710        (epcEvent->size > 0) &&
711        (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
712   {
713     const char* lockFile = static_cast< const char* >( epcEvent->data );
714     mLock = new Indicator::LockFile( lockFile );
715     if( mLock->RetrieveAndClearErrorStatus() )
716     {
717       DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", lockFile );
718     }
719   }
720 }
721
722 void Indicator::Resize( int width, int height )
723 {
724   if( width < 1 )
725   {
726     width = 1;
727   }
728   if( height < 1 )
729   {
730     height = 1;
731   }
732
733   if( mImageWidth != width || mImageHeight != height )
734   {
735     mImageWidth = width;
736     mImageHeight = height;
737
738     // We don't currently handle the pixel buffer size being changed. Create a new image instead
739     if( mSharedFile )
740     {
741       CreateNewImage();
742     }
743   }
744 }
745
746 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
747 {
748   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
749
750   // epcEvent->ref == w
751   // epcEvent->ref_to == h
752   // epcEvent->response == alpha
753   // epcEvent->data = shm ref string + nul byte
754   if( ( epcEvent->data ) &&
755       ( ( unsigned char * ) epcEvent->data)[ epcEvent->size - 1 ] == 0 )
756   {
757     if( mSharedFile != NULL )
758     {
759       delete mSharedFile;
760       mSharedFile = NULL;
761     }
762
763     if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
764     {
765       mImageWidth  = epcEvent->ref;
766       mImageHeight = epcEvent->ref_to;
767
768       char* sharedFilename = static_cast<char*>(epcEvent->data);
769
770       mSharedFile = SharedFile::New( sharedFilename, mImageWidth * mImageWidth * 4, true );
771       if( mSharedFile != NULL )
772       {
773         CreateNewImage();
774         if( CheckVisibleState() )
775         {
776           // set default indicator type (enable the quick panel)
777           OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
778         }
779         else
780         {
781           // set default indicator type (disable the quick panel)
782           OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
783         }
784       }
785     }
786   }
787 }
788
789 void Indicator::UpdateImageData()
790 {
791   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s\n", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
792
793   if( mState == CONNECTED && mVisible )
794   {
795     CopyToBuffer();
796   }
797 }
798
799 bool Indicator::CopyToBuffer()
800 {
801   bool success = false;
802
803   if( mLock )
804   {
805     Indicator::ScopedLock scopedLock(mLock);
806     if( mLock->RetrieveAndClearErrorStatus() )
807     {
808       // Do nothing here.
809     }
810     else if( scopedLock.IsLocked() )
811     {
812       unsigned char *src = mSharedFile->GetAddress();
813       size_t size = mImageWidth * mImageHeight * 4;
814       if( mIndicatorBuffer->UpdatePixels( src, size ) )
815       {
816         mAdaptor->RequestUpdateOnce();
817         success = true;
818       }
819     }
820   }
821
822   return success;
823 }
824
825 void Indicator::SetBackground()
826 {
827   if( ! mBackgroundActor )
828   {
829     ConstructBackgroundMesh();
830   }
831
832   switch( mOpacityMode )
833   {
834     case Dali::Window::TRANSLUCENT:
835     {
836       SetMeshDataColors( mBackgroundMesh, GRADIENT_COLORS );
837     }
838     break;
839
840     case Dali::Window::TRANSPARENT:
841     {
842       SetMeshDataColors( mBackgroundMesh, Color::TRANSPARENT );
843     }
844     break;
845
846     case Dali::Window::OPAQUE:
847     default :
848     {
849       SetMeshDataColors( mBackgroundMesh, Color::BLACK );
850     }
851     break;
852   }
853 }
854
855 void Indicator::CreateNewImage()
856 {
857   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d\n", mImageWidth, mImageHeight );
858   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mImageWidth, mImageHeight, Pixel::BGRA8888 );
859   Dali::Image image = Dali::Image::New( mIndicatorBuffer->GetNativeImage() );
860
861   if( CopyToBuffer() ) // Only create images if we have valid image buffer
862   {
863     mIndicatorImageActor.SetImage( image );
864     mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
865     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
866
867     SetBackground();
868     if( mBackgroundActor )
869     {
870       mBackgroundActor.SetSize( mImageWidth, mImageHeight );
871     }
872   }
873   else
874   {
875     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
876     Disconnect();
877     if( mObserver != NULL )
878     {
879       mObserver->IndicatorClosed( this );
880     }
881     // Don't do connection in this callback - strange things happen!
882     StartReconnectionTimer();
883   }
884 }
885
886 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
887 {
888   if( mObserver != NULL )
889   {
890     mObserver->IndicatorTypeChanged( indicatorType );
891   }
892 }
893
894 void Indicator::DataReceived( void* event )
895 {
896   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
897   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
898
899   switch( epcEvent->minor )
900   {
901     case OP_UPDATE:
902       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
903       break;
904
905     case OP_UPDATE_DONE:
906       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE\n" );
907       UpdateImageData();
908       break;
909
910     case OP_LOCK_FILE:
911       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_LOCK_FILE\n" );
912       NewLockFile( epcEvent );
913       break;
914
915     case OP_SHM_REF:
916       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF\n" );
917       LoadSharedImage( epcEvent );
918       break;
919
920     case OP_RESIZE:
921       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
922
923       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
924       {
925         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
926         Resize( newSize->w, newSize->h );
927       }
928       break;
929
930     case OP_MSG_PARENT:
931     {
932       int msgDomain = epcEvent->ref;
933       int msgId = epcEvent->ref_to;
934       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
935       {
936         switch( msgId )
937         {
938           case MSG_ID_INDICATOR_TYPE:
939           {
940             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
941             Type* indicatorType = static_cast<Type*>( epcEvent->data );
942             OnIndicatorTypeChanged( *indicatorType );
943             break;
944           }
945         }
946       }
947       break;
948     }
949   }
950 }
951
952 void Indicator::ConnectionClosed()
953 {
954   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
955
956   // Will get this callback if the server connection failed to start up.
957   delete mServerConnection;
958   mServerConnection = NULL;
959   mState = DISCONNECTED;
960
961   // Attempt to re-connect
962   Connect(mOrientation);
963 }
964
965 bool Indicator::CheckVisibleState()
966 {
967   if( mOrientation == Dali::Window::LANDSCAPE
968     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
969     || mOpacityMode == Dali::Window::TRANSPARENT
970     || mVisible == false )
971   {
972     return false;
973   }
974
975   return true;
976 }
977
978 void Indicator::ConstructBackgroundMesh()
979 {
980   // Construct 5 interval mesh
981   // 0  +---+  1
982   //    | \ |
983   // 2  +---+  3
984   //    | \ |
985   // 4  +---+  5
986   //    | \ |
987   // 6  +---+  7
988   //    | \ |
989   // 8  +---+  9
990   //    | \ |
991   // 10 +---+  11
992   Dali::AnimatableMesh::Faces faces;
993   faces.reserve(NUM_GRADIENT_INTERVALS * 6); // 2 tris per interval
994   for(int i=0; i<NUM_GRADIENT_INTERVALS; i++)
995   {
996     int j=i*2;
997     faces.push_back(j); faces.push_back(j+3); faces.push_back(j+1);
998     faces.push_back(j); faces.push_back(j+2); faces.push_back(j+3);
999   }
1000
1001   mBackgroundMesh = Dali::AnimatableMesh::New((NUM_GRADIENT_INTERVALS+1)*2, faces);
1002   float interval=1.0f / (float)NUM_GRADIENT_INTERVALS;
1003   for(int i=0;i<NUM_GRADIENT_INTERVALS+1;i++)
1004   {
1005     int j=i*2;
1006     mBackgroundMesh[j  ].SetPosition(Vector3(-0.5f, -0.5f+(interval*(float)i), 0.0f));
1007     mBackgroundMesh[j+1].SetPosition(Vector3( 0.5f, -0.5f+(interval*(float)i), 0.0f));
1008   }
1009
1010   mBackgroundActor = Dali::MeshActor::New(mBackgroundMesh);
1011   mBackgroundActor.SetAffectedByLighting(false);
1012   Dali::ShaderEffect shaderEffect = Dali::ShaderEffect::New( MESH_VERTEX_SHADER, MESH_FRAGMENT_SHADER,
1013                                                              GEOMETRY_TYPE_MESH, // Using vertex color
1014                                                              Dali::ShaderEffect::HINT_BLENDING );
1015   mBackgroundActor.SetShaderEffect(shaderEffect);
1016 }
1017
1018
1019 } // Adaptor
1020 } // Internal
1021 } // Dali