// 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 class FunctorHolder: public CallbackHolder { public: /// This type. typedef FunctorHolder 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)); } static void kill(CallbackHolder* self) { // Destroy functor static_cast( self )->m_functor.~Functor(); } Functor m_functor; ///< the functor to use when a signal is emitted. }; /// Callback with no arguments. template struct Callback0 { static ReturnType callback(CallbackHolder* base) { static_cast< FunctorHolder* >( base )->m_functor(); return ReturnType(); } static CallbackFunc functionAddress() { return reinterpret_cast(&callback); } }; /// Callback with one argument template struct Callback1 { typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1); static ReturnType callback(CallbackHolder* base, Arg1 arg1) { static_cast< FunctorHolder* >( base )->m_functor(arg1); return ReturnType(); } static CallbackFunc functionAddress() { return reinterpret_cast(&callback); } }; /// Callback with two arguments template struct Callback2 { typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2); static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2) { static_cast< FunctorHolder* >( base )->m_functor(arg1, arg2); return ReturnType(); } static CallbackFunc functionAddress() { return reinterpret_cast(&callback); } }; /// Callback with three arguments template struct Callback3 { typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3); static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2, Arg3 arg3) { static_cast< FunctorHolder* >( base )->m_functor( arg1, arg2, arg3 ); return ReturnType(); } static CallbackFunc functionAddress() { return reinterpret_cast(&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 class Slot0: public SlotHolder { public: typedef ReturnType (*CallbackType)(CallbackHolder*); template Slot0( const Functor& functor ): SlotHolder( new FunctorHolder (functor, Callback0::functionAddress())) { } void operator()() { reinterpret_cast(m_holder->m_callback)( m_holder ); } }; /// Slot with one argument. template class Slot1:public SlotHolder { public: typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1); template Slot1( const Functor& functor ): SlotHolder( new FunctorHolder (functor, Callback1::functionAddress())){ } void operator()(Arg1 arg) { reinterpret_cast(m_holder->m_callback)(m_holder, arg); } }; /// Slot with two arguments template class Slot2: public SlotHolder { public: typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2); template Slot2( const Functor& functor ): SlotHolder( new FunctorHolder (functor, Callback2::functionAddress())){ } void operator()(Arg1 arg1, Arg2 arg2) { reinterpret_cast(m_holder->m_callback)(m_holder, arg1, arg2); } }; /// Slot with three arguments template class Slot3: public SlotHolder { public: typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3); template Slot3( const Functor& functor ): SlotHolder( new FunctorHolder (functor, Callback3::functionAddress())){ } void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) { reinterpret_cast(m_holder->m_callback) ( m_holder, arg1, arg2, arg3 ); } }; } // namespace SigImpl } // namespace FbTk #endif // FBTK_SLOT_H