2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "ecore-callback-manager.h"
24 #include <dali/integration-api/debug.h>
39 * Structure contains the callback function and control options
44 * the type of callback
48 STANDARD_CALLBACK, ///< either an idle call back, or a default call back
49 EVENT_HANDLER ///< event handler
55 CallbackData(CallbackManager::Callback callback, CallbackType type):
59 mPriority(CallbackManager::DEFAULT_PRIORITY),
63 mEventControl(CallbackManager::CALLBACK_PASS_ON)
68 CallbackManager::Callback mCallback; ///< call back
69 CallbackType mType; ///< type of call back
71 // Data for idle / default call backs
72 Ecore_Idler* mIdler; ///< ecore idler
73 CallbackManager::Priority mPriority; ///< Priority (idle or normal)
74 bool mExecute; ///< whether to run the callback
76 // Data for event handlers
77 Ecore_Event_Handler* mEventHandler; ///< ecore handler
78 int mEvent; ///< ecore event id
79 CallbackManager::EventControl mEventControl; ///< event control
81 // function typedef to remove the callbackdata from the callback container
82 typedef boost::function<void(CallbackData *)> RemoveFromContainerFunction;
84 RemoveFromContainerFunction mRemoveFromContainerFunction;
91 * Called from the main thread while idle.
93 Eina_Bool IdleCallback(void *data)
95 CallbackData *callbackData = static_cast<CallbackData *>(data);
97 // remove callback data from the container first in case our callback tries to modify the container
98 callbackData->mRemoveFromContainerFunction(callbackData);
101 callbackData->mCallback();
103 // remove the idle call back
104 ecore_idler_del(callbackData->mIdler);
108 return ECORE_CALLBACK_CANCEL;
112 * Ecore callback event handler, called from the main thread
113 * @param data user data
114 * @param type event type, e.g. ECORE_EVENT_SIGNAL_EXIT
115 * @param event pointer to ecore event
117 Eina_Bool EventHandler(void *data, int type, void *event)
119 CallbackData* callbackData = static_cast<CallbackData*>(data);
121 // make sure the type is for the right event
122 DALI_ASSERT_ALWAYS( type == callbackData->mEvent && "Callback data does not match event" );
124 // remove callback data from the container first in case our callback tries to modify the container
125 callbackData->mRemoveFromContainerFunction(callbackData);
128 callbackData->mCallback();
132 if (callbackData->mEventControl == CallbackManager::CALLBACK_PASS_ON)
134 returnVal = ECORE_CALLBACK_PASS_ON;
138 returnVal = ECORE_CALLBACK_DONE;
147 * called from MainLoopCallback to process standard callbacks
149 void AddStandardCallback(CallbackData *callbackData)
151 if (callbackData->mPriority == CallbackManager::IDLE_PRIORITY)
153 // run the call back on idle
154 callbackData->mIdler = ecore_idler_add(IdleCallback, callbackData);
155 DALI_ASSERT_ALWAYS( callbackData->mIdler != NULL && "Idle method not created" );
159 // run the call back now, then delete it from the container
160 if ( callbackData->mExecute )
162 callbackData->mCallback();
164 callbackData->mRemoveFromContainerFunction(callbackData);
170 * called from MainLoopCallback to add event callbacks
172 void AddEventCallback(CallbackData *callbackData)
174 callbackData->mEventHandler = ecore_event_handler_add(callbackData->mEvent, &EventHandler, callbackData);
178 * main loop call back to process call back data.
180 void MainLoopCallback(void *data)
182 CallbackData *callbackData = static_cast< CallbackData* >(data);
184 if (callbackData->mType == CallbackData::STANDARD_CALLBACK)
186 AddStandardCallback(callbackData);
188 else if (callbackData->mType == CallbackData::EVENT_HANDLER)
190 AddEventCallback(callbackData);
195 * Main loop call back to remove all call back data
197 void* MainRemoveAllCallback(void* data)
199 EcoreCallbackManager *callbackManager = static_cast<EcoreCallbackManager *>(data);
201 callbackManager->RemoveAllCallbacksFromMainThread();
206 } // unnamed namespace
208 EcoreCallbackManager::EcoreCallbackManager()
213 void EcoreCallbackManager::RemoveStandardCallback(CallbackData *callbackData)
215 if (callbackData->mPriority == CallbackManager::IDLE_PRIORITY)
217 // delete the idle call back
218 ecore_idler_del(callbackData->mIdler);
223 // ecore doesn't give us a handle for functions we want executing on the
224 // main thread, E.g. we can't do
225 // handle = ecore_main_loop_thread_safe_call_async( myfunc )
226 // ecore_main_loop_thread_remove_async_call(handle); // doesn't exist
228 // We just have to set a flag to say do not execute.
229 // Hence we can't delete the call back at this point.
230 callbackData->mExecute = false;
234 void EcoreCallbackManager::RemoveEventCallback(CallbackData *callbackData)
236 ecore_event_handler_del(callbackData->mEventHandler);
241 void EcoreCallbackManager::Start()
243 DALI_ASSERT_DEBUG( mRunning == false );
248 void EcoreCallbackManager::Stop()
250 // make sure we're not called twice
251 DALI_ASSERT_DEBUG( mRunning == true );
253 // lock out any other call back functions
254 boost::unique_lock< boost::mutex > lock( mMutex );
258 // the synchronous calls return data from the callback, which we ignore.
259 ecore_main_loop_thread_safe_call_sync(MainRemoveAllCallback, this);
262 bool EcoreCallbackManager::AddCallback(Callback callback, Priority priority)
268 CallbackData *callbackData = new CallbackData(callback, CallbackData::STANDARD_CALLBACK);
270 callbackData->mPriority = priority;
272 callbackData->mRemoveFromContainerFunction = boost::bind(&EcoreCallbackManager::RemoveCallbackFromContainer, this,_1);
274 { // acquire lock to access container
275 boost::unique_lock< boost::mutex > lock( mMutex );
277 // add the call back to the container
278 mCallbackContainer.push_front(callbackData);
281 // Get callbackData processed on the main loop..
283 ecore_main_loop_thread_safe_call_async(MainLoopCallback, callbackData);
291 bool EcoreCallbackManager::AddEventCallback(Callback callback, int type, EventControl control)
297 CallbackData *callbackData = new CallbackData(callback,CallbackData::EVENT_HANDLER);
298 callbackData->mEventControl = control;
299 callbackData->mEvent = type;
301 callbackData->mRemoveFromContainerFunction = boost::bind(&EcoreCallbackManager::RemoveCallbackFromContainer, this,_1);
303 { // acquire lock to access container
304 boost::unique_lock< boost::mutex > lock( mMutex );
306 // add the call back to the container
307 mCallbackContainer.push_front(callbackData);
310 // Get callbackData processed on the main loop..
311 ecore_main_loop_thread_safe_call_async(MainLoopCallback, callbackData);
319 void EcoreCallbackManager::RemoveCallbackFromContainer(CallbackData *callbackData)
321 // always called from main loop
322 boost::unique_lock< boost::mutex > lock( mMutex );
324 mCallbackContainer.remove(callbackData);
327 void EcoreCallbackManager::RemoveAllCallbacksFromMainThread()
329 // always called from main thread
330 // the mutex will already be locked at this point
332 for( CallbackList::iterator iter = mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter)
334 CallbackData* data = (*iter);
336 if (data->mType == CallbackData::STANDARD_CALLBACK)
338 RemoveStandardCallback(data);
340 else if (data->mType == CallbackData::EVENT_HANDLER)
342 RemoveEventCallback(data);
345 mCallbackContainer.clear();
348 // Creates a concrete interface for CallbackManager
349 CallbackManager* CallbackManager::New()
351 return new EcoreCallbackManager;
354 } // namespace Adaptor
356 } // namespace Internal