all repos — fluxbox @ e4d4717703b365bc14f189bf36b3edb1e4430b90

custom fork of the fluxbox windowmanager

Added new Signal/Slot system in FbTk

This is suppose to replace the obsolete Subject/Observer classes.
See the src/tests/testSignals.cc for basic usage.
Henrik Kinnunen fluxgen@fluxbox.org
commit

e4d4717703b365bc14f189bf36b3edb1e4430b90

parent

8e97963e4211963f960c52c8a8f4bf5cd135ad2f

M ChangeLogChangeLog

@@ -1,4 +1,9 @@

(Format: Year/Month/Day) +Changes for 1.1.2: +*08/09/18: + * Added new Signal/Slot system to FbTk (Henrik) + This is suppose to replace the obsolete Subject/Observer classes. + FbTk/Signal.hh, FbTk/Slot.hh, FbTk/MemFun.hh, tests/testSignals.cc Changes for 1.1.1 *08/09/14: * Fixed a minor pixmap resource leak (Henrik)
M src/FbTk/Makefile.amsrc/FbTk/Makefile.am

@@ -63,6 +63,7 @@ stringstream.hh \

TypeAhead.hh SearchResult.hh SearchResult.cc ITypeAheadable.hh \ Select2nd.hh STLUtil.hh \ CachedPixmap.hh CachedPixmap.cc \ + Slot.hh Signal.hh MemFun.hh \ ${xpm_SOURCE} \ ${xft_SOURCE} \ ${xmb_SOURCE} \
A src/FbTk/MemFun.hh

@@ -0,0 +1,139 @@

+// MemFun.hh for FbTk, Fluxbox Toolkit +// Copyright (c) 2008 Henrik Kinnunen (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef FBTK_MEM_FUN_HH +#define FBTK_MEM_FUN_HH + +namespace FbTk { + +/// No argument functor +template <typename ReturnType, typename Object> +class MemFun0 { +public: + typedef ReturnType (Object:: *Action)(); + + MemFun0(Object& obj, Action action): + m_obj(obj), + m_action(action) { + } + + void operator ()() { + (m_obj.*m_action)(); + } + +private: + Object& m_obj; + Action m_action; +}; + + +template <typename ReturnType, typename Object> +MemFun0<ReturnType, Object> +MemFun( Object& obj, ReturnType (Object:: *action)() ) { + return MemFun0<ReturnType, Object>(obj, action); +} + +/// One argument functor +template <typename ReturnType, typename Object, typename Arg1> +class MemFun1 { +public: + typedef ReturnType (Object:: *Action)(Arg1); + + MemFun1(Object& obj, Action action): + m_obj(obj), + m_action(action) { + } + + void operator ()(Arg1 arg1) { + (m_obj.*m_action)(arg1); + } + +private: + Object& m_obj; + Action m_action; +}; + +/// One argument functor helper function +template <typename ReturnType, typename Object, typename Arg1> +MemFun1<ReturnType, Object, Arg1> +MemFun( Object& obj, ReturnType (Object:: *action)(Arg1) ) { + return MemFun1<ReturnType, Object, Arg1>(obj, action); +} + +/// Two argument functor +template <typename ReturnType, typename Object, typename Arg1, typename Arg2> +class MemFun2 { +public: + typedef ReturnType (Object:: *Action)(Arg1,Arg2); + + MemFun2(Object& obj, Action action): + m_obj(obj), + m_action(action) { + } + + void operator ()(Arg1 arg1, Arg2 arg2) { + (m_obj.*m_action)(arg1, arg2); + } + +private: + Object& m_obj; + Action m_action; +}; + +/// Two argument functor helper function +template <typename ReturnType, typename Object, typename Arg1, typename Arg2> +MemFun2<ReturnType, Object, Arg1, Arg2> +MemFun( Object& obj, ReturnType (Object:: *action)(Arg1,Arg2) ) { + return MemFun2<ReturnType, Object, Arg1, Arg2>(obj, action); +} + +/// Three argument functor +template <typename ReturnType, typename Object, + typename Arg1, typename Arg2, typename Arg3> +class MemFun3 { +public: + typedef ReturnType (Object:: *Action)(Arg1,Arg2,Arg3); + + MemFun3(Object& obj, Action action): + m_obj(obj), + m_action(action) { + } + + void operator ()(Arg1 arg1, Arg2 arg2, Arg3 arg3) { + (m_obj.*m_action)(arg1, arg2, arg3); + } + +private: + Object& m_obj; + Action m_action; +}; + +/// Three argument functor helper +template <typename ReturnType, typename Object, typename Arg1, typename Arg2, typename Arg3> +MemFun3<ReturnType, Object, Arg1, Arg2, Arg3> +MemFun( Object& obj, ReturnType (Object:: *action)(Arg1, Arg2, Arg3) ) { + return MemFun3<ReturnType, Object, Arg1, Arg2, Arg3>(obj, action); +} + +} // namespace FbTk + +#endif // FBTK_MEM_FUN_HH +
A src/FbTk/Signal.hh

@@ -0,0 +1,218 @@

+// Signal.hh for FbTk, Fluxbox Toolkit +// Copyright (c) 2008 Henrik Kinnunen (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef FBTK_SIGNAL_HH +#define FBTK_SIGNAL_HH + +#include "Slot.hh" +#include <list> +#include <vector> + +namespace FbTk { + +/// \namespace Implementation details for signals, do not use anything in this namespace +namespace SigImpl { + +/** + * Parent class for all \c Signal[0...*] classes. + * It handles the disconnect and holds all the slots. The connect must be + * handled by the child class so it can do the type checking. + */ +class SignalHolder { +public: + /// Do not use this type outside this class + typedef std::list<SlotHolder> SlotList; + + typedef SlotList::iterator Iterator; + typedef Iterator SlotID; + typedef SlotList::const_iterator ConstIterator; + + /// Remove a specific slot \c id from this signal + void disconnect(SlotID slotIt) { + m_slots.erase( slotIt ); + } + + + /// Removes all slots connected to this + void clear() { + m_slots.clear(); + } + +protected: + ConstIterator begin() const { return m_slots.begin(); } + ConstIterator end() const { return m_slots.end(); } + + Iterator begin() { return m_slots.begin(); } + Iterator end() { return m_slots.end(); } + + /// Connect a slot to this signal. Must only be called by child classes. + SlotID connect(const SlotHolder& slot) { + return m_slots.insert(m_slots.end(), slot); + } + +private: + SlotList m_slots; ///< all slots connected to a signal +}; + +/// Signal with no argument +template <typename ReturnType> +class Signal0: public SignalHolder { +public: + typedef Slot0<ReturnType> SlotType; + + void emit() { + for ( Iterator it = begin(); it != end(); ++it ) { + static_cast<SlotType&>(*it)(); + } + } + + SlotID connect(const SlotType& slot) { + return SignalHolder::connect(slot); + + } +}; + +/// Signal with one argument +template <typename ReturnType, typename Arg1> +class Signal1: public SignalHolder { +public: + typedef Slot1<ReturnType, Arg1> SlotType; + + void emit(Arg1 arg) { + for ( Iterator it = begin(); it != end(); ++it ) { + static_cast<SlotType&>(*it)(arg); + } + } + + SlotID connect(const SlotType& slot) { + return SignalHolder::connect(slot); + } + +}; + +/// Signal with two arguments +template <typename ReturnType, typename Arg1, typename Arg2> +class Signal2: public SignalHolder { +public: + typedef Slot2<ReturnType, Arg1, Arg2> SlotType; + + void emit(Arg1 arg1, Arg2 arg2) { + for ( Iterator it = begin(); it != end(); ++it ) { + static_cast<SlotType&>(*it)(arg1, arg2); + } + } + + SlotID connect(const SlotType& slot) { + return SignalHolder::connect(slot); + } +}; + +/// Signal with three arguments +template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3> +class Signal3: public SignalHolder { +public: + typedef Slot3<ReturnType, Arg1, Arg2, Arg3> SlotType; + + void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) { + for ( Iterator it = begin(); it != end(); ++it ) { + static_cast<SlotType&>(*it)(arg1, arg2, arg3); + } + } + + SlotID connect(const SlotType& slot) { + return SignalHolder::connect(slot); + } + +}; + +struct EmptyArg {}; + +} // namespace SigImpl + + +/// Specialization for three arguments. +template <typename ReturnType, + typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg > +class Signal: public SigImpl::Signal3< ReturnType, Arg1, Arg2, Arg3 > { +public: +}; + +/// Specialization for two arguments. +template <typename ReturnType, typename Arg1, typename Arg2> +class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::Signal2< ReturnType, Arg1, Arg2 > { +public: +}; + +/// Specialization for one argument. +template <typename ReturnType, typename Arg1> +class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::Signal1< ReturnType, Arg1 > { +public: +}; + +/// Specialization for no argument. +template <typename ReturnType> +class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::Signal0< ReturnType > { +public: +}; + +/** + * Tracks a signal during it's life time. All signals connected using \c + * SignalTracker::join will be erased when this instance dies. + */ +class SignalTracker { +public: + /// Internal type, do not use. + typedef std::list< std::pair< SigImpl::SignalHolder*, SigImpl::SignalHolder::SlotID > > Connections; + typedef Connections::iterator TrackID; ///< \c ID type for join/leave. + + ~SignalTracker() { + // disconnect all connections + for ( Connections::iterator conIt = m_connections.begin(); + conIt != m_connections.end(); ) { + conIt->first->disconnect( conIt->second ); + conIt = m_connections.erase( conIt ); + } + } + + /// Starts tracking a signal. + /// @return A tracking ID ( not unique ) + template <typename Signal, typename Functor> + TrackID join(Signal& sig, const Functor& functor) { + return + m_connections.insert(m_connections.end(), + Connections::value_type(&sig, sig.connect(functor))); + } + + /// Leave tracking for a signal + /// @param id the \c id from the previous \c join + void leave(TrackID id) { + m_connections.erase(id); + } + +private: + /// holds all connections to different signals and slots. + Connections m_connections; +}; + + +} // namespace FbTk + +#endif // FBTK_SIGNAL_HH
A src/FbTk/Slot.hh

@@ -0,0 +1,294 @@

+// Slot.hh for FbTk, Fluxbox Toolkit +// Copyright (c) 2008 Henrik Kinnunen (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef FBTK_SLOT_HH +#define FBTK_SLOT_HH + +namespace FbTk { + +/// \namespace Implementation details for signals, do not use anything in this namespace +namespace SigImpl { + +class CallbackHolder; + +/// Placeholder type for typed callbacks +typedef void* (*CallbackFunc)(void *); +/// Clone function callback type for cloning typed callback holders +typedef CallbackHolder* (*CloneFunc)(CallbackHolder*); +/// Kill function callback type for destroying type specific information in +/// FunctorHolder +typedef void (*KillFunc)(CallbackHolder*); + +/// Holds clone, functor callback, and the kill function for FunctorHolder. +class CallbackHolder { +public: + /** + * @param callback The callback to call when a slot receives a signal. + * @param clone The callback to use for cloning a type specific instance of + * this classinstance. + * @param kill The callback that knows how to free the memory in type + * specific instance of this class. + */ + CallbackHolder(CallbackFunc callback, + CloneFunc clone, + KillFunc kill): + m_callback(callback), + m_kill(kill), + m_clone(clone) { } + + ~CallbackHolder() { + (*m_kill)(this); + } + + /// @return a clone of this instance + CallbackHolder* clone() { + return (*m_clone)(this); + } + + /// \c Callback to \c Functor specific callback + CallbackFunc m_callback; + +protected: + + CallbackHolder& operator = (const CallbackHolder& other) { + if ( this == &other ) { + return *this; + } + m_callback = other.m_callback; + m_clone = other.m_clone; + m_kill = other.m_kill; + + return *this; + } + + CallbackHolder(const CallbackHolder& other) { + *this = other; + } + +private: + /// This function is called to kill this instance + KillFunc m_kill; + /// Functions that knows how to clone a specific \c Functor type + CloneFunc m_clone; +}; + + +/// Holds the functor and creates a clone callback for \c Functor specific type +template <typename Functor> +class FunctorHolder: public CallbackHolder { +public: + /// This type. + typedef FunctorHolder<Functor> Self; + /** + * @param functor The functor to be used when a signal is emitted. + * @param callback The callback to call when a signal is emitted. + */ + FunctorHolder(const Functor& functor, CallbackFunc callback): + CallbackHolder(callback, &clone, &kill), + m_functor(functor) { + } + + /// Specific clone for this Functor type + static CallbackHolder* clone(CallbackHolder* self) { + return new Self( static_cast<Self&>(*self)); + } + + static void kill(CallbackHolder* self) { + // Destroy functor + static_cast<Self*>( self )->m_functor.~Functor(); + } + + Functor m_functor; ///< the functor to use when a signal is emitted. +}; + + + +/// Callback with no arguments. +template <typename Functor, typename ReturnType > +struct Callback0 { + static ReturnType callback(CallbackHolder* base) { + static_cast< FunctorHolder<Functor>* >( base )->m_functor(); + return ReturnType(); + } + + static CallbackFunc functionAddress() { + return reinterpret_cast<CallbackFunc>(&callback); + } +}; + +/// Callback with one argument +template <typename Functor, typename ReturnType, typename Arg1> +struct Callback1 { + typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1); + + static ReturnType callback(CallbackHolder* base, Arg1 arg1) { + static_cast< FunctorHolder<Functor>* >( base )->m_functor(arg1); + return ReturnType(); + } + + static CallbackFunc functionAddress() { + return reinterpret_cast<CallbackFunc>(&callback); + } +}; + +/// Callback with two arguments +template <typename Functor, typename ReturnType, + typename Arg1, typename Arg2> +struct Callback2 { + typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2); + + static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2) { + static_cast< FunctorHolder<Functor>* >( base )->m_functor(arg1, arg2); + return ReturnType(); + } + + static CallbackFunc functionAddress() { + return reinterpret_cast<CallbackFunc>(&callback); + } +}; + +/// Callback with three arguments +template <typename Functor, typename ReturnType, + typename Arg1, typename Arg2, typename Arg3> +struct Callback3 { + typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3); + + static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2, Arg3 arg3) { + static_cast< FunctorHolder<Functor>* >( base )->m_functor( arg1, arg2, arg3 ); + return ReturnType(); + } + + static CallbackFunc functionAddress() { + return reinterpret_cast<CallbackFunc>(&callback); + } +}; + +/// Holds callback holder and handles the copying of callback holders for the +/// \c Slots. +class SlotHolder { +public: + SlotHolder(const SlotHolder& other): + m_holder( other.m_holder ? other.m_holder->clone() : 0 ) { + } + + ~SlotHolder() { + delete m_holder; + } + + SlotHolder& operator = (const SlotHolder& other) { + if ( &other == this ) { + return *this; + } + delete m_holder; + if ( other.m_holder ) { + m_holder = other.m_holder->clone(); + } else { + m_holder = 0; + } + return *this; + } + + SlotHolder():m_holder( 0 ) { } + +protected: + explicit SlotHolder(CallbackHolder* holder): + m_holder( holder ) { + } + + CallbackHolder* m_holder; +}; + +/// Slot with no argument. +template <typename ReturnType> +class Slot0: public SlotHolder { +public: + typedef ReturnType (*CallbackType)(CallbackHolder*); + + template <typename Functor> + Slot0( const Functor& functor ): + SlotHolder( new FunctorHolder<Functor> + (functor, Callback0<Functor, ReturnType>::functionAddress())) { + } + + void operator()() { + reinterpret_cast<CallbackType>(m_holder->m_callback)( m_holder ); + } +}; + +/// Slot with one argument. +template <typename ReturnType, typename Arg1> +class Slot1:public SlotHolder { +public: + typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1); + + template <typename Functor> + Slot1( const Functor& functor ): + SlotHolder( new FunctorHolder<Functor> + (functor, Callback1<Functor, ReturnType, Arg1>::functionAddress())){ + + } + + void operator()(Arg1 arg) { + reinterpret_cast<CallbackType>(m_holder->m_callback)(m_holder, arg); + } + +}; + +/// Slot with two arguments +template <typename ReturnType, typename Arg1, typename Arg2> +class Slot2: public SlotHolder { +public: + typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2); + template <typename Functor> + Slot2( const Functor& functor ): + SlotHolder( new FunctorHolder<Functor> + (functor, Callback2<Functor, ReturnType, Arg1, Arg2>::functionAddress())){ + + } + + void operator()(Arg1 arg1, Arg2 arg2) { + reinterpret_cast<CallbackType>(m_holder->m_callback)(m_holder, arg1, arg2); + } +}; + +/// Slot with three arguments +template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3> +class Slot3: public SlotHolder { +public: + typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3); + template <typename Functor> + Slot3( const Functor& functor ): + SlotHolder( new FunctorHolder<Functor> + (functor, Callback3<Functor, ReturnType, Arg1, Arg2, Arg3>::functionAddress())){ + + } + + void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) { + reinterpret_cast<CallbackType>(m_holder->m_callback) + ( m_holder, arg1, arg2, arg3 ); + } +}; + +} // namespace SigImpl + +} // namespace FbTk + +#endif // FBTK_SLOT_H
M src/tests/Makefilesrc/tests/Makefile

@@ -7,13 +7,17 @@ COMPILEFILE=$(CXX) -c $(CXXFLAGS)

FONT_OBJ = ../FbTk/libFbTk.a COMPILE = ${CXX} ${CXXFLAGS} ${XLIBS} -all: testMenu testFont testTexture movetest +all: testMenu testFont testTexture movetest testSignals + .cc.o: $(CXX) -c $(CXXFLAGS) $< glxtest: ../FbTk/App.hh glxtest.cc ${CXX} glxtest.cc ${CXXFLAGS} ${XLIBS} -lGL -lGLU -lXpm -o glxtest + +testSignals: testSignals.o ../FbTk/Signal.hh ../FbTk/MemFun.hh + $(CXX) $(LIBS) testSignals.o -o testSignals testStringUtil: StringUtiltest.o $(CXX) $(LIBS) StringUtiltest.o ../FbTk/libFbTk.a -o testStringUtil
A src/tests/testSignals.cc

@@ -0,0 +1,121 @@

+#include <iostream> +using namespace std; + +#include "../FbTk/Signal.hh" +#include "../FbTk/MemFun.hh" + +#include <string> + + + +struct NoArgument { + void operator() () const { + cout << "No Argument." << endl; + } +}; + +struct OneArgument { + void operator ()( int value ) { + cout << "One argument = " << value << endl; + } +}; + +struct TwoArguments { + void operator ()( int value, const string& message ) { + cout << "Two arguments, (1) = " << value << ", (2) = " << message << endl; + } +}; + +struct ThreeArguments { + void operator ()( int value, const string& message, double value2 ) { + cout << "Two arguments, (1) = " << value << ", (2) = " << message + << ", (3) = " << value2 << endl; + } +}; + +struct FunctionClass { + FunctionClass() { + cout << "FunctionClass created." << endl; + } + ~FunctionClass() { + cout << "FunctionClass deleted." << endl; + } + void print() { + cout << "Printing." << endl; + } + + void takeIt( string& str ) { + cout << "takeIt( " << str << ")" << endl; + } + + void showMessage( int value, const string& message ) { + cout << "(" << value << "): " << message << endl; + } + void threeArgs( int value, const string& str, double pi ) { + cout << "(" << value << "): " << str << ", pi = " << pi << endl; + } +}; + +int main() { + using FbTk::Signal; + using FbTk::SignalTracker; + + Signal<void> no_arg; + no_arg.connect( NoArgument() ); + + Signal<void, int> one_arg; + one_arg.connect( OneArgument() ); + + Signal<void, int, const string&> two_args; + two_args.connect( TwoArguments() ); + + Signal<void, int, const string&, double> three_args; + three_args.connect( ThreeArguments() ); + + // emit test + no_arg.emit(); + one_arg.emit( 10 ); + two_args.emit( 10, "Message" ); + three_args.emit( 10, "Three", 3.141592 ); + + // test signal tracker + { + cout << "---- tracker ----" << endl; + SignalTracker tracker; + // setup two new slots and track them + SignalTracker::TrackID id_no_arg = tracker.join( no_arg, NoArgument() ); + SignalTracker::TrackID id_one_arg = tracker.join( one_arg, OneArgument() ); + + // two outputs each from these two signals + no_arg.emit(); + one_arg.emit( 31 ); + + // stop tracking id_one_arg, which should keep the slot after this scope, + // the id_no_arg connection should be destroyed after this. + tracker.leave( id_one_arg ); + cout << "---- tracker end ----" << endl; + } + + // now we should have one output from no_arg and two outputs from one_arg + no_arg.emit(); + one_arg.emit( 2 ); + + using FbTk::MemFun; + FunctionClass obj; + no_arg.clear(); + no_arg.connect(MemFun(obj, &FunctionClass::print)); + no_arg.emit(); + + string takeThis("Take this"); + Signal<void, string&> ref_arg; + ref_arg.connect(MemFun(obj, &FunctionClass::takeIt)); + ref_arg.emit( takeThis ); + + two_args.clear(); + two_args.connect(MemFun(obj, &FunctionClass::showMessage)); + two_args.emit(10, "This is a message"); + + three_args.clear(); + three_args.connect(MemFun(obj, &FunctionClass::threeArgs)); + three_args.emit(9, "nine", 3.141592); +}