1 #ifndef __DALI_BASE_SIGNAL_H__
2 #define __DALI_BASE_SIGNAL_H__
5 * Copyright (c) 2014 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>
28 namespace Dali DALI_IMPORT_API
32 * @brief Implementation class for Dali::SignalV2%s.
34 * A slot can be connected to many signals
35 * A signal can be connected to many slots
37 * To provide automatic disconnection when either a signal or the object owning the slot dies,
40 * A signal is an object with state. It holds a list of SignalConnection%s.
43 * Signal OnTouch. mSignalConnections contains
45 * <tr><td> %Callback 0 </td><td> Signal Observer 0 </td></tr>
46 * <tr><td> %Callback 1 </td><td> Signal Observer 1 </td></tr>
47 * <tr><td> %Callback 2 </td><td> Signal Observer 2 </td></tr>
50 * OnTouch.Emit() will run callbacks 0, 1 and 2.
52 * When the signal is destroyed. SignalDisconnected() is called on each Signal Observer.
54 * Slots are just static or member functions, so have no state. E.g. they can't keep
55 * track of how many signals they are connected to.
56 * If the object owning a slot dies, it must automatically disconnected from all signals.
57 * If it doesn't disconnect and the signal is emitted, there will be a crash.
59 * To keep track of connections between slots and signals, a Connection tracker is used.
60 * It holds a list of SlotConnections.
63 * <tr><td> %Callback 0 </td><td> Slot Observer 0 </td></tr>
64 * <tr><td> %Callback 1 </td><td> Slot Observer 1 </td></tr>
65 * <tr><td> %Callback 2 </td><td> Slot Observer 2 </td></tr>
68 * When the connection tracker is destroyed, SlotDisconnected() is called on every slot observer ( signal )
69 * Signals implement the Slot Observer interface, to be told when a slot has disconnected
70 * Connection tracker implements the Signal Observer interface, to be told when a signal has disconnected (died)
73 class BaseSignal : public SlotObserver
83 * @brief Virtual destructor.
85 virtual ~BaseSignal();
88 * @brief Query whether there are any connected slots.
90 * @return True if there are any slots connected to the signal.
95 * @brief Query the number of slots.
97 * @return The number of slots connected to this signal.
99 std::size_t GetConnectionCount() const;
101 // Templated Emit functions for the Signal implementations
104 * @brief Used to guard against nested Emit() calls.
109 * @brief Create the guard.
111 * @param[in,out] flag This flag will be set to true during Emit() calls.
113 EmitGuard( bool& flag );
116 * @brief Non-virtual destructor.
122 * @brief Determine if an error occured.
124 * @return True if an error occurred i.e. if Emit() was called during Emit()
126 bool ErrorOccurred();
128 bool* mFlag; ///< Pointer to the emit guard flag.
132 * @brief Emit a signal with no parameters.
134 * @pre Cannot be called from inside the same Signal's Emit methods.
139 * @brief Emit a signal with no parameters.
141 * @pre Cannot be called from inside the same Signal's Emit methods.
142 * @return The value returned by the last callback.
144 template< typename Ret >
147 Ret returnVal = Ret();
149 // Guards against nested Emit() calls
150 EmitGuard guard( mEmittingFlag );
151 if( guard.ErrorOccurred() )
156 // If more connections are added by callbacks, these are ignore until the next Emit()
157 // Note that count cannot be reduced while iterating
158 const std::size_t initialCount( mSignalConnections.Count() );
160 for( std::size_t i = 0; i < initialCount; ++i )
162 CallbackBase* callback( GetCallback(i) );
164 // Note that connections will be set to NULL when disconnected
165 // This is preferable to reducing the connection count while iterating
168 returnVal = CallbackBase::ExecuteReturn<Ret>( *callback );
172 // Cleanup NULL values from Connection container
173 CleanupConnections();
179 * @brief Emit a signal with 1 parameter.
181 * @pre Cannot be called from inside the same Signal's Emit methods.
182 * @param[in] arg0 The first parameter.
184 template< typename Arg0 >
185 void Emit( Arg0 arg0 )
187 // Guards against nested Emit() calls
188 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
189 if( guard.ErrorOccurred() )
194 // If more connections are added by callbacks, these are ignore until the next Emit()
195 // Note that count cannot be reduced while iterating
196 const std::size_t initialCount( mSignalConnections.Count() );
198 for( std::size_t i = 0; i < initialCount; ++i )
200 CallbackBase* callback( GetCallback(i) );
202 // Note that connections will be set to NULL when disconnected
203 // This is preferable to reducing the connection count while iterating
206 CallbackBase::Execute<Arg0 >( *callback, arg0 );
210 // Cleanup NULL values from Connection container
211 CleanupConnections();
215 * @brief Emit a signal with 1 parameter.
217 * @pre Cannot be called from inside the same Signal's Emit methods.
218 * @param[in] arg0 The first parameter.
219 * @return The value returned by the last callback.
221 template< typename Ret, typename Arg0 >
222 Ret EmitReturn( Arg0 arg0 )
224 Ret returnVal = Ret();
226 // Guards against nested Emit() calls
227 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
228 if( guard.ErrorOccurred() )
233 // If more connections are added by callbacks, these are ignore until the next Emit()
234 // Note that count cannot be reduced while iterating
235 const std::size_t initialCount( mSignalConnections.Count() );
237 for( std::size_t i = 0; i < initialCount; ++i )
239 CallbackBase* callback( GetCallback(i) );
241 // Note that connections will be set to NULL when disconnected
242 // This is preferable to reducing the connection count while iterating
245 returnVal = CallbackBase::ExecuteReturn<Ret,Arg0>( *callback, arg0 );
249 // Cleanup NULL values from Connection container
250 CleanupConnections();
256 * @brief Emit a signal with 2 parameters.
258 * @pre Cannot be called from inside the same Signal's Emit methods.
259 * @param[in] arg0 The first parameter.
260 * @param[in] arg1 The second parameter.
262 template< typename Arg0, typename Arg1 >
263 void Emit( Arg0 arg0, Arg1 arg1 )
265 // Guards against nested Emit() calls
266 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
267 if( guard.ErrorOccurred() )
272 // If more connections are added by callbacks, these are ignore until the next Emit()
273 // Note that count cannot be reduced while iterating
274 const std::size_t initialCount( mSignalConnections.Count() );
276 for( std::size_t i = 0; i < initialCount; ++i )
278 CallbackBase* callback( GetCallback(i) );
280 // Note that connections will be set to NULL when disconnected
281 // This is preferable to reducing the connection count while iterating
284 CallbackBase::Execute<Arg0,Arg1>( *callback, arg0, arg1 );
288 // Cleanup NULL values from Connection container
289 CleanupConnections();
293 * @brief Emit a signal with 2 parameters.
295 * @pre Cannot be called from inside the same Signal's Emit methods.
296 * @param[in] arg0 The first parameter.
297 * @param[in] arg1 The second parameter.
298 * @return The value returned by the last callback.
300 template< typename Ret, typename Arg0, typename Arg1 >
301 Ret EmitReturn( Arg0 arg0, Arg1 arg1 )
303 Ret returnVal = Ret();
305 // Guards against nested Emit() calls
306 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
307 if( guard.ErrorOccurred() )
312 // If more connections are added by callbacks, these are ignore until the next Emit()
313 // Note that count cannot be reduced while iterating
314 const std::size_t initialCount( mSignalConnections.Count() );
316 for( std::size_t i = 0; i < initialCount; ++i )
318 CallbackBase* callback( GetCallback(i) );
320 // Note that connections will be set to NULL when disconnected
321 // This is preferable to reducing the connection count while iterating
324 returnVal = CallbackBase::ExecuteReturn<Ret,Arg0,Arg1>( *callback, arg0, arg1 );
328 // Cleanup NULL values from Connection container
329 CleanupConnections();
335 * @brief Emit a signal with 3 parameters.
337 * @pre Cannot be called from inside the same Signal's Emit methods.
338 * @param[in] arg0 The first parameter.
339 * @param[in] arg1 The second parameter.
340 * @param[in] arg2 The third parameter.
342 template< typename Arg0, typename Arg1, typename Arg2 >
343 void Emit( Arg0 arg0, Arg1 arg1, Arg2 arg2 )
345 // Guards against nested Emit() calls
346 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
347 if( guard.ErrorOccurred() )
352 // If more connections are added by callbacks, these are ignore until the next Emit()
353 // Note that count cannot be reduced while iterating
354 const std::size_t initialCount( mSignalConnections.Count() );
356 for( std::size_t i = 0; i < initialCount; ++i )
358 CallbackBase* callback( GetCallback(i) );
360 // Note that connections will be set to NULL when disconnected
361 // This is preferable to reducing the connection count while iterating
364 CallbackBase::Execute<Arg0,Arg1,Arg2>( *callback, arg0, arg1, arg2 );
368 // Cleanup NULL values from Connection container
369 CleanupConnections();
373 * @brief Emit a signal with 3 parameters.
375 * @pre Cannot be called from inside the same Signal's Emit methods.
376 * @param[in] arg0 The first parameter.
377 * @param[in] arg1 The second parameter.
378 * @param[in] arg2 The third parameter.
379 * @return The value returned by the last callback.
381 template< typename Ret, typename Arg0, typename Arg1, typename Arg2 >
382 Ret EmitReturn( Arg0 arg0, Arg1 arg1, Arg2 arg2 )
384 Ret returnVal = Ret();
386 // Guards against nested Emit() calls
387 EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
388 if( guard.ErrorOccurred() )
393 // If more connections are added by callbacks, these are ignore until the next Emit()
394 // Note that count cannot be reduced while iterating
395 const std::size_t initialCount( mSignalConnections.Count() );
397 for( std::size_t i = 0; i < initialCount; ++i )
399 CallbackBase* callback( GetCallback(i) );
401 // Note that connections will be set to NULL when disconnected
402 // This is preferable to reducing the connection count while iterating
405 returnVal = CallbackBase::ExecuteReturn<Ret,Arg0,Arg1,Arg2>( *callback, arg0, arg1, arg2 );
409 // Cleanup NULL values from Connection container
410 CleanupConnections();
415 // Connect / Disconnect function for use by Signal implementations
418 * @brief Called by Signal implementations, when the user calls Signal.Connect( ... )
420 * @param[in] callback A newly allocated callback object (takes ownership).
422 void OnConnect( CallbackBase* callback );
425 * @brief Called by Signal implementations, when the user calls Signal.Disconnect( ... )
427 * @param[in] callback A newly allocated callback object (takes ownership).
429 void OnDisconnect( CallbackBase* callback );
432 * @brief Called by Signal implementations, when the user calls Signal.Connect( ... )
434 * @param[in] tracker The connection tracker.
435 * @param[in] callback A newly allocated callback object (takes ownership).
437 void OnConnect( ConnectionTrackerInterface* tracker, CallbackBase* callback );
440 * @brief Called by Signal implementations, when the user calls Signal.Disconnect( ... )
442 * @param[in] tracker The connection tracker.
443 * @param[in] callback A newly allocated callback object (takes ownership).
445 void OnDisconnect( ConnectionTrackerInterface* tracker, CallbackBase* callback );
447 private: // SlotObserver interface, to be told when a slot disconnects
450 * @copydoc SlotObserver::SlotDisconnected
452 virtual void SlotDisconnected( CallbackBase* callback );
457 * @brief Returns a callback given an index in to the connection array.
459 * @param[in] connectionIndex The index of the callback.
460 * @return The callback, or NULL if the connection has been deleted.
462 CallbackBase* GetCallback( std::size_t connectionIndex ) const;
465 * @brief Helper to find whether a callback is connected.
467 * @param[in] callback The call back object.
468 * @return A valid index if the callback is connected.
470 int FindCallback( CallbackBase* callback );
473 * @brief Deletes a connection object from the list of connections.
475 * @param[in] connectionIndex The index of the callback.
477 void DeleteConnection( std::size_t connectionIndex );
480 * @brief Helper to remove NULL items from mSignalConnections, which is only safe at the end of Emit()
481 * i.e. not from methods which can be called during a signal Emit(), such as Disconnect().
483 void CleanupConnections();
485 BaseSignal( const BaseSignal& ); ///< undefined copy constructor, signals don't support copying.
486 BaseSignal& operator=( const BaseSignal& ); ///< undefined assignment operator
490 Dali::Vector< SignalConnection* > mSignalConnections; ///< Array of connections
492 bool mEmittingFlag; ///< Used to guard against nested Emit() calls
497 #endif // __DALI_BASE_SIGNAL_H__