1 #ifndef __DALI_BASE_SIGNAL_H__
2 #define __DALI_BASE_SIGNAL_H__
5 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/signals/callback.h>
25 #include <dali/public-api/signals/connection-tracker-interface.h>
26 #include <dali/public-api/signals/signal-slot-connections.h>
31 * @addtogroup dali_core_signals
36 * @brief Implementation class for Dali::Signal.
38 * A slot can be connected to many signals
39 * A signal can be connected to many slots
41 * To provide automatic disconnection when either a signal or the object owning the slot dies,
44 * A signal is an object with state. It holds a list of SignalConnection%s.
47 * Signal OnTouch. mSignalConnections contains
49 * <tr><td> %Callback 0 </td><td> Signal Observer 0 </td></tr>
50 * <tr><td> %Callback 1 </td><td> Signal Observer 1 </td></tr>
51 * <tr><td> %Callback 2 </td><td> Signal Observer 2 </td></tr>
54 * OnTouch.Emit() will run callbacks 0, 1 and 2.
56 * When the signal is destroyed. SignalDisconnected() is called on each Signal Observer.
58 * Slots are just static or member functions, so have no state. E.g. they can't keep
59 * track of how many signals they are connected to.
60 * If the object owning a slot dies, it must automatically disconnected from all signals.
61 * If it doesn't disconnect and the signal is emitted, there will be a crash.
63 * To keep track of connections between slots and signals, a Connection tracker is used.
64 * It holds a list of SlotConnections.
67 * <tr><td> %Callback 0 </td><td> Slot Observer 0 </td></tr>
68 * <tr><td> %Callback 1 </td><td> Slot Observer 1 </td></tr>
69 * <tr><td> %Callback 2 </td><td> Slot Observer 2 </td></tr>
72 * When the connection tracker is destroyed, SlotDisconnected() is called on every slot observer ( signal )
73 * Signals implement the Slot Observer interface, to be told when a slot has disconnected
74 * Connection tracker implements the Signal Observer interface, to be told when a signal has disconnected (died)
77 class DALI_IMPORT_API BaseSignal : public SlotObserver
87 * @brief Virtual destructor.
89 virtual ~BaseSignal();
92 * @brief Query whether there are any connected slots.
94 * @return True if there are any slots connected to the signal.
99 * @brief Query the number of slots.
101 * @return The number of slots connected to this signal.
103 std::size_t GetConnectionCount() const;
105 // Templated Emit functions for the Signal implementations
108 * @brief Used to guard against nested Emit() calls.
113 * @brief Create the guard.
115 * @param[in,out] flag This flag will be set to true during Emit() calls.
117 EmitGuard( bool& flag );
120 * @brief Non-virtual destructor.
126 * @brief Determine if an error occured.
128 * @return True if an error occurred i.e. if Emit() was called during Emit()
130 bool ErrorOccurred();
132 bool* mFlag; ///< Pointer to the emit guard flag.
136 * @brief Emit a signal with no parameters.
138 * @pre Cannot be called from inside the same Signal's Emit methods.
143 * @brief Emit a signal with no parameters.
145 * @pre Cannot be called from inside the same Signal's Emit methods.
146 * @return The value returned by the last callback.
148 template< typename Ret >
151 Ret returnVal = Ret();
153 // Guards against nested Emit() calls
154 EmitGuard guard( mEmittingFlag );
155 if( guard.ErrorOccurred() )
160 // If more connections are added by callbacks, these are ignore until the next Emit()
161 // Note that count cannot be reduced while iterating
162 const std::size_t initialCount( mSignalConnections.Count() );
164 for( std::size_t i = 0; i < initialCount; ++i )
166 CallbackBase* callback( GetCallback(i) );
168 // Note that connections will be set to NULL when disconnected
169 // This is preferable to reducing the connection count while iterating
172 returnVal = CallbackBase::ExecuteReturn<Ret>( *callback );
176 // Cleanup NULL values from Connection container
177 CleanupConnections();
183 * @brief Emit a signal with 1 parameter.
185 * @pre Cannot be called from inside the same Signal's Emit methods.
186 * @param[in] arg0 The first parameter.
188 template< typename Arg0 >
189 void Emit( Arg0 arg0 )
191 // Guards against nested Emit() calls
192 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
193 if( guard.ErrorOccurred() )
198 // If more connections are added by callbacks, these are ignore until the next Emit()
199 // Note that count cannot be reduced while iterating
200 const std::size_t initialCount( mSignalConnections.Count() );
202 for( std::size_t i = 0; i < initialCount; ++i )
204 CallbackBase* callback( GetCallback(i) );
206 // Note that connections will be set to NULL when disconnected
207 // This is preferable to reducing the connection count while iterating
210 CallbackBase::Execute<Arg0 >( *callback, arg0 );
214 // Cleanup NULL values from Connection container
215 CleanupConnections();
219 * @brief Emit a signal with 1 parameter.
221 * @pre Cannot be called from inside the same Signal's Emit methods.
222 * @param[in] arg0 The first parameter.
223 * @return The value returned by the last callback.
225 template< typename Ret, typename Arg0 >
226 Ret EmitReturn( Arg0 arg0 )
228 Ret returnVal = Ret();
230 // Guards against nested Emit() calls
231 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
232 if( guard.ErrorOccurred() )
237 // If more connections are added by callbacks, these are ignore until the next Emit()
238 // Note that count cannot be reduced while iterating
239 const std::size_t initialCount( mSignalConnections.Count() );
241 for( std::size_t i = 0; i < initialCount; ++i )
243 CallbackBase* callback( GetCallback(i) );
245 // Note that connections will be set to NULL when disconnected
246 // This is preferable to reducing the connection count while iterating
249 returnVal = CallbackBase::ExecuteReturn<Ret,Arg0>( *callback, arg0 );
253 // Cleanup NULL values from Connection container
254 CleanupConnections();
260 * @brief Emit a signal with 2 parameters.
262 * @pre Cannot be called from inside the same Signal's Emit methods.
263 * @param[in] arg0 The first parameter.
264 * @param[in] arg1 The second parameter.
266 template< typename Arg0, typename Arg1 >
267 void Emit( Arg0 arg0, Arg1 arg1 )
269 // Guards against nested Emit() calls
270 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
271 if( guard.ErrorOccurred() )
276 // If more connections are added by callbacks, these are ignore until the next Emit()
277 // Note that count cannot be reduced while iterating
278 const std::size_t initialCount( mSignalConnections.Count() );
280 for( std::size_t i = 0; i < initialCount; ++i )
282 CallbackBase* callback( GetCallback(i) );
284 // Note that connections will be set to NULL when disconnected
285 // This is preferable to reducing the connection count while iterating
288 CallbackBase::Execute<Arg0,Arg1>( *callback, arg0, arg1 );
292 // Cleanup NULL values from Connection container
293 CleanupConnections();
297 * @brief Emit a signal with 2 parameters.
299 * @pre Cannot be called from inside the same Signal's Emit methods.
300 * @param[in] arg0 The first parameter.
301 * @param[in] arg1 The second parameter.
302 * @return The value returned by the last callback.
304 template< typename Ret, typename Arg0, typename Arg1 >
305 Ret EmitReturn( Arg0 arg0, Arg1 arg1 )
307 Ret returnVal = Ret();
309 // Guards against nested Emit() calls
310 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
311 if( guard.ErrorOccurred() )
316 // If more connections are added by callbacks, these are ignore until the next Emit()
317 // Note that count cannot be reduced while iterating
318 const std::size_t initialCount( mSignalConnections.Count() );
320 for( std::size_t i = 0; i < initialCount; ++i )
322 CallbackBase* callback( GetCallback(i) );
324 // Note that connections will be set to NULL when disconnected
325 // This is preferable to reducing the connection count while iterating
328 returnVal = CallbackBase::ExecuteReturn<Ret,Arg0,Arg1>( *callback, arg0, arg1 );
332 // Cleanup NULL values from Connection container
333 CleanupConnections();
339 * @brief Emit a signal with 3 parameters.
341 * @pre Cannot be called from inside the same Signal's Emit methods.
342 * @param[in] arg0 The first parameter.
343 * @param[in] arg1 The second parameter.
344 * @param[in] arg2 The third parameter.
346 template< typename Arg0, typename Arg1, typename Arg2 >
347 void Emit( Arg0 arg0, Arg1 arg1, Arg2 arg2 )
349 // Guards against nested Emit() calls
350 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
351 if( guard.ErrorOccurred() )
356 // If more connections are added by callbacks, these are ignore until the next Emit()
357 // Note that count cannot be reduced while iterating
358 const std::size_t initialCount( mSignalConnections.Count() );
360 for( std::size_t i = 0; i < initialCount; ++i )
362 CallbackBase* callback( GetCallback(i) );
364 // Note that connections will be set to NULL when disconnected
365 // This is preferable to reducing the connection count while iterating
368 CallbackBase::Execute<Arg0,Arg1,Arg2>( *callback, arg0, arg1, arg2 );
372 // Cleanup NULL values from Connection container
373 CleanupConnections();
377 * @brief Emit a signal with 3 parameters.
379 * @pre Cannot be called from inside the same Signal's Emit methods.
380 * @param[in] arg0 The first parameter.
381 * @param[in] arg1 The second parameter.
382 * @param[in] arg2 The third parameter.
383 * @return The value returned by the last callback.
385 template< typename Ret, typename Arg0, typename Arg1, typename Arg2 >
386 Ret EmitReturn( Arg0 arg0, Arg1 arg1, Arg2 arg2 )
388 Ret returnVal = Ret();
390 // Guards against nested Emit() calls
391 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
392 if( guard.ErrorOccurred() )
397 // If more connections are added by callbacks, these are ignore until the next Emit()
398 // Note that count cannot be reduced while iterating
399 const std::size_t initialCount( mSignalConnections.Count() );
401 for( std::size_t i = 0; i < initialCount; ++i )
403 CallbackBase* callback( GetCallback(i) );
405 // Note that connections will be set to NULL when disconnected
406 // This is preferable to reducing the connection count while iterating
409 returnVal = CallbackBase::ExecuteReturn<Ret,Arg0,Arg1,Arg2>( *callback, arg0, arg1, arg2 );
413 // Cleanup NULL values from Connection container
414 CleanupConnections();
419 // Connect / Disconnect function for use by Signal implementations
422 * @brief Called by Signal implementations, when the user calls Signal.Connect( ... )
424 * @param[in] callback A newly allocated callback object (takes ownership).
426 void OnConnect( CallbackBase* callback );
429 * @brief Called by Signal implementations, when the user calls Signal.Disconnect( ... )
431 * @param[in] callback A newly allocated callback object (takes ownership).
433 void OnDisconnect( CallbackBase* callback );
436 * @brief Called by Signal implementations, when the user calls Signal.Connect( ... )
438 * @param[in] tracker The connection tracker.
439 * @param[in] callback A newly allocated callback object (takes ownership).
441 void OnConnect( ConnectionTrackerInterface* tracker, CallbackBase* callback );
444 * @brief Called by Signal implementations, when the user calls Signal.Disconnect( ... )
446 * @param[in] tracker The connection tracker.
447 * @param[in] callback A newly allocated callback object (takes ownership).
449 void OnDisconnect( ConnectionTrackerInterface* tracker, CallbackBase* callback );
451 private: // SlotObserver interface, to be told when a slot disconnects
454 * @copydoc SlotObserver::SlotDisconnected
456 virtual void SlotDisconnected( CallbackBase* callback );
461 * @brief Returns a callback given an index in to the connection array.
463 * @param[in] connectionIndex The index of the callback.
464 * @return The callback, or NULL if the connection has been deleted.
466 CallbackBase* GetCallback( std::size_t connectionIndex ) const;
469 * @brief Helper to find whether a callback is connected.
471 * @param[in] callback The call back object.
472 * @return A valid index if the callback is connected.
474 int FindCallback( CallbackBase* callback );
477 * @brief Deletes a connection object from the list of connections.
479 * @param[in] connectionIndex The index of the callback.
481 void DeleteConnection( std::size_t connectionIndex );
484 * @brief Helper to remove NULL items from mSignalConnections, which is only safe at the end of Emit()
485 * i.e. not from methods which can be called during a signal Emit(), such as Disconnect().
487 void CleanupConnections();
489 BaseSignal( const BaseSignal& ); ///< undefined copy constructor, signals don't support copying.
490 BaseSignal& operator=( const BaseSignal& ); ///< undefined assignment operator
494 Dali::Vector< SignalConnection* > mSignalConnections; ///< Array of connections
496 bool mEmittingFlag; ///< Used to guard against nested Emit() calls
504 #endif // __DALI_BASE_SIGNAL_H__