Merge "Move environment variable parsing to environment options" into tizen
[platform/core/uifw/dali-adaptor.git] / adaptors / common / ecore-callback-manager.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "ecore-callback-manager.h"
20
21 // EXTERNAL INCLUDES
22 #include <Ecore.h>
23
24 #include <dali/integration-api/debug.h>
25
26 // INTERNAL INCLUDES
27
28
29 namespace Dali
30 {
31
32 namespace Internal
33 {
34
35 namespace Adaptor
36 {
37
38 /**
39  * Structure contains the callback function and control options
40  */
41 struct CallbackData
42 {
43   /**
44    * the type of callback
45    */
46   enum CallbackType
47   {
48     STANDARD_CALLBACK,  ///< either an idle call back, or a default call back
49     EVENT_HANDLER       ///< event handler
50   };
51
52   /**
53    * Constructor
54    */
55   CallbackData( CallbackBase* callback, CallbackType type )
56   :  mCallback(callback),
57      mType(type),
58      mIdler(NULL),
59      mPriority(CallbackManager::DEFAULT_PRIORITY),
60      mExecute(true),
61      mEventHandler(NULL),
62      mEvent(0),
63      mEventControl(CallbackManager::CALLBACK_PASS_ON),
64      mRemoveFromContainerFunction(NULL)
65   {
66   }
67
68   /**
69    * Destructor
70    */
71   ~CallbackData()
72   {
73     delete mCallback;
74     delete mRemoveFromContainerFunction;
75   }
76
77   // Data
78   CallbackBase*                   mCallback;      ///< call back
79   CallbackType                    mType;          ///< type of call back
80
81     // Data for idle / default call backs
82   Ecore_Idler*                    mIdler;         ///< ecore idler
83   CallbackManager::Priority       mPriority;      ///< Priority (idle or normal)
84   bool                            mExecute;       ///< whether to run the callback
85
86   // Data for event handlers
87   Ecore_Event_Handler*            mEventHandler;  ///< ecore handler
88   int                             mEvent;         ///< ecore event id
89   CallbackManager::EventControl   mEventControl;  ///< event control
90
91   CallbackBase*                   mRemoveFromContainerFunction; ///< Called to remove the callbackdata from the callback container
92 };
93
94 namespace
95 {
96
97 /**
98  * Called from the main thread while idle.
99  */
100 Eina_Bool IdleCallback(void *data)
101 {
102   CallbackData *callbackData = static_cast<CallbackData *>(data);
103
104   // remove callback data from the container first in case our callback tries to modify the container
105   CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
106
107   // run the function
108   CallbackBase::Execute( *callbackData->mCallback );
109
110   // remove the idle call back
111   ecore_idler_del(callbackData->mIdler);
112
113   delete callbackData;
114
115   return ECORE_CALLBACK_CANCEL;
116 }
117
118 /**
119  * Ecore callback event handler, called from the main thread
120  * @param data  user data
121  * @param type event type, e.g. ECORE_EVENT_SIGNAL_EXIT
122  * @param event pointer to ecore event
123  */
124 Eina_Bool EventHandler(void *data, int type, void *event)
125 {
126   CallbackData* callbackData = static_cast<CallbackData*>(data);
127
128   // make sure the type is for the right event
129   DALI_ASSERT_ALWAYS( type == callbackData->mEvent && "Callback data does not match event" );
130
131   // remove callback data from the container first in case our callback tries to modify the container
132   CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
133
134   // run the call back
135   CallbackBase::Execute( *callbackData->mCallback );
136
137   Eina_Bool returnVal;
138
139   if (callbackData->mEventControl == CallbackManager::CALLBACK_PASS_ON)
140   {
141     returnVal = ECORE_CALLBACK_PASS_ON;
142   }
143   else
144   {
145     returnVal = ECORE_CALLBACK_DONE;
146   }
147
148   delete callbackData;
149
150   return returnVal;
151 }
152
153 /**
154  * called from MainLoopCallback to process standard callbacks
155  */
156 void AddStandardCallback(CallbackData *callbackData)
157 {
158   if (callbackData->mPriority == CallbackManager::IDLE_PRIORITY)
159   {
160     // run the call back on idle
161     callbackData->mIdler = ecore_idler_add(IdleCallback, callbackData);
162     DALI_ASSERT_ALWAYS( callbackData->mIdler != NULL && "Idle method not created" );
163   }
164   else
165   {
166     // run the call back now, then delete it from the container
167     if ( callbackData->mExecute )
168     {
169       CallbackBase::Execute( *callbackData->mCallback );
170     }
171     CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
172     delete callbackData;
173   }
174 }
175
176 /**
177  * called from MainLoopCallback to add event callbacks
178  */
179 void AddEventCallback(CallbackData *callbackData)
180 {
181   callbackData->mEventHandler = ecore_event_handler_add(callbackData->mEvent, &EventHandler, callbackData);
182 }
183
184 /**
185  * main loop call back to process call back data.
186  */
187 void MainLoopCallback(void *data)
188 {
189   CallbackData *callbackData = static_cast< CallbackData* >(data);
190
191   if (callbackData->mType ==  CallbackData::STANDARD_CALLBACK)
192   {
193     AddStandardCallback(callbackData);
194   }
195   else if (callbackData->mType ==  CallbackData::EVENT_HANDLER)
196   {
197     AddEventCallback(callbackData);
198   }
199 }
200
201 /**
202  * Main loop call back to remove all call back data
203  */
204 void* MainRemoveAllCallback(void* data)
205 {
206   EcoreCallbackManager *callbackManager = static_cast<EcoreCallbackManager *>(data);
207
208   callbackManager->RemoveAllCallbacksFromMainThread();
209
210   return NULL;
211 }
212
213 } // unnamed namespace
214
215 EcoreCallbackManager::EcoreCallbackManager()
216 :mRunning(false)
217 {
218 }
219
220 void EcoreCallbackManager::RemoveStandardCallback(CallbackData *callbackData)
221 {
222   if (callbackData->mPriority == CallbackManager::IDLE_PRIORITY)
223   {
224     // delete the idle call back
225     ecore_idler_del(callbackData->mIdler);
226     delete callbackData;
227   }
228   else
229   {
230     // ecore doesn't give us a handle for functions we want executing on the
231     // main thread, E.g. we can't do
232     // handle = ecore_main_loop_thread_safe_call_async( myfunc )
233     // ecore_main_loop_thread_remove_async_call(handle);  // doesn't exist
234     //
235     // We just have to set a flag to say do not execute.
236     // Hence we can't delete the call back at this point.
237     callbackData->mExecute = false;
238   }
239 }
240
241 void EcoreCallbackManager::RemoveEventCallback(CallbackData *callbackData)
242 {
243   ecore_event_handler_del(callbackData->mEventHandler);
244
245   delete callbackData;
246 }
247
248 void EcoreCallbackManager::Start()
249 {
250   DALI_ASSERT_DEBUG( mRunning == false );
251
252   mRunning = true;
253 }
254
255 void EcoreCallbackManager::Stop()
256 {
257   // make sure we're not called twice
258   DALI_ASSERT_DEBUG( mRunning == true );
259
260   // lock out any other call back functions
261   boost::unique_lock< boost::mutex > lock( mMutex );
262
263   mRunning = false;
264
265   // the synchronous calls return data from the callback, which we ignore.
266   ecore_main_loop_thread_safe_call_sync(MainRemoveAllCallback, this);
267 }
268
269 bool EcoreCallbackManager::AddCallback(CallbackBase* callback, Priority priority)
270 {
271   bool added(false);
272
273   if ( mRunning )
274   {
275     CallbackData *callbackData = new CallbackData(callback, CallbackData::STANDARD_CALLBACK);
276
277     callbackData->mPriority = priority;
278
279     callbackData->mRemoveFromContainerFunction =  MakeCallback( this, &EcoreCallbackManager::RemoveCallbackFromContainer );
280
281     { // acquire lock to access container
282       boost::unique_lock< boost::mutex > lock( mMutex );
283
284       // add the call back to the container
285       mCallbackContainer.push_front(callbackData);
286     }
287
288     // Get callbackData processed on the main loop..
289
290     ecore_main_loop_thread_safe_call_async(MainLoopCallback, callbackData);
291
292     added = true;
293   }
294
295   return added;
296 }
297
298 bool EcoreCallbackManager::AddEventCallback(CallbackBase* callback, int type, EventControl control)
299 {
300   bool added(false);
301
302   if( mRunning )
303   {
304     CallbackData *callbackData = new CallbackData(callback,CallbackData::EVENT_HANDLER);
305     callbackData->mEventControl = control;
306     callbackData->mEvent = type;
307
308     callbackData->mRemoveFromContainerFunction =  MakeCallback( this, &EcoreCallbackManager::RemoveCallbackFromContainer );
309
310     { // acquire lock to access container
311       boost::unique_lock< boost::mutex > lock( mMutex );
312
313       // add the call back to the container
314       mCallbackContainer.push_front(callbackData);
315     }
316
317     // Get callbackData processed on the main loop..
318     ecore_main_loop_thread_safe_call_async(MainLoopCallback, callbackData);
319
320     added = true;
321   }
322
323   return added;
324 }
325
326 void EcoreCallbackManager::RemoveCallbackFromContainer(CallbackData *callbackData)
327 {
328   // always called from main loop
329   boost::unique_lock< boost::mutex > lock( mMutex );
330
331   mCallbackContainer.remove(callbackData);
332 }
333
334 void EcoreCallbackManager::RemoveAllCallbacksFromMainThread()
335 {
336    // always called from main thread
337    // the mutex will already be locked at this point
338
339    for( CallbackList::iterator  iter =  mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter)
340    {
341      CallbackData* data = (*iter);
342
343      if (data->mType ==  CallbackData::STANDARD_CALLBACK)
344      {
345        RemoveStandardCallback(data);
346      }
347      else if (data->mType ==  CallbackData::EVENT_HANDLER)
348      {
349        RemoveEventCallback(data);
350      }
351    }
352    mCallbackContainer.clear();
353 }
354
355 // Creates a concrete interface for CallbackManager
356 CallbackManager* CallbackManager::New()
357 {
358   return new EcoreCallbackManager;
359 }
360
361 } // namespace Adaptor
362
363 } // namespace Internal
364
365 } // namespace Dali