301 lines
9.9 KiB
C
301 lines
9.9 KiB
C
|
// -*- c++ -*-
|
||
|
/*
|
||
|
* Copyright 2002, The libsigc++ Development Team
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef _SIGC_SIGNAL_BASE_H_
|
||
|
#define _SIGC_SIGNAL_BASE_H_
|
||
|
|
||
|
#include <list>
|
||
|
#include <sigc++config.h>
|
||
|
#include <sigc++/type_traits.h>
|
||
|
#include <sigc++/trackable.h>
|
||
|
#include <sigc++/functors/slot.h>
|
||
|
#include <sigc++/functors/mem_fun.h>
|
||
|
|
||
|
namespace sigc
|
||
|
{
|
||
|
|
||
|
namespace internal
|
||
|
{
|
||
|
|
||
|
/** Implementation of the signal interface.
|
||
|
* signal_impl manages a list of slots. When a slot becomes
|
||
|
* invalid (because some referred object dies), notify() is executed.
|
||
|
* notify() either calls sweep() directly or defers the execution of
|
||
|
* sweep() when the signal is being emitted. sweep() removes all
|
||
|
* invalid slot from the list.
|
||
|
*/
|
||
|
struct SIGC_API signal_impl
|
||
|
{
|
||
|
typedef size_t size_type;
|
||
|
typedef std::list<slot_base> slot_list;
|
||
|
typedef slot_list::iterator iterator_type;
|
||
|
typedef slot_list::const_iterator const_iterator_type;
|
||
|
|
||
|
signal_impl();
|
||
|
|
||
|
// only MSVC needs this to guarantee that all new/delete are executed from the DLL module
|
||
|
#ifdef SIGC_NEW_DELETE_IN_LIBRARY_ONLY
|
||
|
void* operator new(size_t size_);
|
||
|
void operator delete(void* p);
|
||
|
#endif
|
||
|
|
||
|
/// Increments the reference counter.
|
||
|
inline void reference()
|
||
|
{ ++ref_count_; }
|
||
|
|
||
|
/// Increments the reference and execution counter.
|
||
|
inline void reference_exec()
|
||
|
{ ++ref_count_; ++exec_count_; }
|
||
|
|
||
|
/** Decrements the reference counter.
|
||
|
* The object is deleted when the reference counter reaches zero.
|
||
|
*/
|
||
|
inline void unreference()
|
||
|
{ if (!(--ref_count_)) delete this; }
|
||
|
|
||
|
/** Decrements the reference and execution counter.
|
||
|
* Invokes sweep() if the execution counter reaches zero and the
|
||
|
* removal of one or more slots has been deferred.
|
||
|
*/
|
||
|
inline void unreference_exec()
|
||
|
{
|
||
|
if (!(--ref_count_)) delete this;
|
||
|
else if (!(--exec_count_) && deferred_) sweep();
|
||
|
}
|
||
|
|
||
|
/** Returns whether the list of slots is empty.
|
||
|
* @return @p true if the list of slots is empty.
|
||
|
*/
|
||
|
inline bool empty() const
|
||
|
{ return slots_.empty(); }
|
||
|
|
||
|
/// Empties the list of slots.
|
||
|
void clear();
|
||
|
|
||
|
/** Returns the number of slots in the list.
|
||
|
* @return The number of slots in the list.
|
||
|
*/
|
||
|
size_type size() const;
|
||
|
|
||
|
/** Adds a slot at the bottom of the list of slots.
|
||
|
* @param slot_ The slot to add to the list of slots.
|
||
|
* @return An iterator pointing to the new slot in the list.
|
||
|
*/
|
||
|
iterator_type connect(const slot_base& slot_);
|
||
|
|
||
|
/** Adds a slot at the given position into the list of slots.
|
||
|
* @param i An iterator indicating the position where @p slot_ should be inserted.
|
||
|
* @param slot_ The slot to add to the list of slots.
|
||
|
* @return An iterator pointing to the new slot in the list.
|
||
|
*/
|
||
|
iterator_type insert(iterator_type i, const slot_base& slot_);
|
||
|
|
||
|
/** Removes the slot at the given position from the list of slots.
|
||
|
* @param i An iterator pointing to the slot to be removed.
|
||
|
* @return An iterator pointing to the slot in the list after the one removed.
|
||
|
*/
|
||
|
iterator_type erase(iterator_type i);
|
||
|
|
||
|
/// Removes invalid slots from the list of slots.
|
||
|
void sweep();
|
||
|
|
||
|
/** Callback that is executed when some slot becomes invalid.
|
||
|
* This callback is registered in every slot when inserted into
|
||
|
* the list of slots. It is executed when a slot becomes invalid
|
||
|
* because of some referred object being destroyed.
|
||
|
* It either calls sweep() directly or defers the execution of
|
||
|
* sweep() when the signal is being emitted.
|
||
|
* @param d The signal object (@p this).
|
||
|
*/
|
||
|
static void* notify(void* d);
|
||
|
|
||
|
/** Reference counter.
|
||
|
* The object is destroyed when @em ref_count_ reaches zero.
|
||
|
*/
|
||
|
short ref_count_;
|
||
|
|
||
|
/** Execution counter.
|
||
|
* Indicates whether the signal is being emitted.
|
||
|
*/
|
||
|
short exec_count_;
|
||
|
|
||
|
/// Indicates whether the execution of sweep() is being deferred.
|
||
|
bool deferred_;
|
||
|
|
||
|
/// The list of slots.
|
||
|
std::list<slot_base> slots_;
|
||
|
};
|
||
|
|
||
|
/// Exception safe sweeper for cleaning up invalid slots on the slot list.
|
||
|
struct SIGC_API signal_exec
|
||
|
{
|
||
|
/// The parent sigc::signal_impl object.
|
||
|
signal_impl* sig_;
|
||
|
|
||
|
/** Increments the reference and execution counter of the parent sigc::signal_impl object.
|
||
|
* @param sig The parent sigc::signal_impl object.
|
||
|
*/
|
||
|
inline signal_exec(const signal_impl* sig)
|
||
|
: sig_(const_cast<signal_impl*>(sig) )
|
||
|
{ sig_->reference_exec(); }
|
||
|
|
||
|
/// Decrements the reference and execution counter of the parent sigc::signal_impl object.
|
||
|
inline ~signal_exec()
|
||
|
{ sig_->unreference_exec(); }
|
||
|
};
|
||
|
|
||
|
/** Temporary slot list used during signal emission.
|
||
|
* Through evolution this class is slightly misnamed. It is now
|
||
|
* an index into the slot_list passed into it. It simply keeps track
|
||
|
* of where the end of this list was at construction, and pretends that's
|
||
|
* the end of your list. This way you may connect during emittion without
|
||
|
* inadvertently entering an infinite loop, as well as make other
|
||
|
* modifications to the slot_list at your own risk.
|
||
|
*/
|
||
|
struct temp_slot_list
|
||
|
{
|
||
|
typedef signal_impl::slot_list slot_list;
|
||
|
typedef signal_impl::iterator_type iterator;
|
||
|
typedef signal_impl::const_iterator_type const_iterator;
|
||
|
|
||
|
temp_slot_list(slot_list &slots) : slots_(slots)
|
||
|
{
|
||
|
placeholder = slots_.insert(slots_.end(), slot_base());
|
||
|
}
|
||
|
|
||
|
~temp_slot_list()
|
||
|
{
|
||
|
slots_.erase(placeholder);
|
||
|
}
|
||
|
|
||
|
iterator begin() { return slots_.begin(); }
|
||
|
iterator end() { return placeholder; }
|
||
|
const_iterator begin() const { return slots_.begin(); }
|
||
|
const_iterator end() const { return placeholder; }
|
||
|
|
||
|
private:
|
||
|
slot_list &slots_;
|
||
|
slot_list::iterator placeholder;
|
||
|
};
|
||
|
|
||
|
} /* namespace internal */
|
||
|
|
||
|
|
||
|
/** @defgroup signal Signals
|
||
|
* Use sigc::signal::connect() with sigc::mem_fun() and sigc::ptr_fun() to connect a method or function with a signal.
|
||
|
*
|
||
|
* @code
|
||
|
* signal_clicked.connect( sigc::mem_fun(*this, &MyWindow::on_clicked) );
|
||
|
* @endcode
|
||
|
*
|
||
|
* When the signal is emitted your method will be called.
|
||
|
*
|
||
|
* signal::connect() returns a connection, which you can later use to disconnect your method.
|
||
|
* If the type of your object inherits from sigc::trackable the method is disconnected
|
||
|
* automatically when your object is destroyed.
|
||
|
*
|
||
|
* When signals are copied they share the underlying information,
|
||
|
* so you can have a protected/private sigc::signal member and a public accessor method.
|
||
|
*
|
||
|
* signal and slot objects provide the core functionality of this
|
||
|
* library. A slot is a container for an arbitrary functor.
|
||
|
* A signal is a list of slots that are executed on emission.
|
||
|
* For compile time type safety a list of template arguments
|
||
|
* must be provided for the signal template that determines the
|
||
|
* parameter list for emission. Functors and closures are converted
|
||
|
* into slots implicitely on connection, triggering compiler errors
|
||
|
* if the given functor or closure cannot be invoked with the
|
||
|
* parameter list of the signal to connect to.
|
||
|
*/
|
||
|
|
||
|
/** Base class for the sigc::signal# templates.
|
||
|
* signal_base integrates most of the interface of the derived sigc::signal#
|
||
|
* templates. The implementation, however, resides in sigc::internal::signal_impl.
|
||
|
* A sigc::internal::signal_impl object is dynamically allocated from signal_base
|
||
|
* when first connecting a slot to the signal. This ensures that empty signals
|
||
|
* don't waste memory.
|
||
|
*
|
||
|
* @ingroup signal
|
||
|
*/
|
||
|
struct SIGC_API signal_base : public trackable
|
||
|
{
|
||
|
typedef size_t size_type;
|
||
|
|
||
|
signal_base();
|
||
|
|
||
|
signal_base(const signal_base& src);
|
||
|
|
||
|
~signal_base();
|
||
|
|
||
|
signal_base& operator = (const signal_base& src);
|
||
|
|
||
|
/** Returns whether the list of slots is empty.
|
||
|
* @return @p true if the list of slots is empty.
|
||
|
*/
|
||
|
inline bool empty() const
|
||
|
{ return (!impl_ || impl_->empty()); }
|
||
|
|
||
|
/// Empties the list of slots.
|
||
|
void clear();
|
||
|
|
||
|
/** Returns the number of slots in the list.
|
||
|
* @return The number of slots in the list.
|
||
|
*/
|
||
|
size_type size() const;
|
||
|
|
||
|
protected:
|
||
|
typedef internal::signal_impl::iterator_type iterator_type;
|
||
|
|
||
|
/** Adds a slot at the end of the list of slots.
|
||
|
* With connect(), slots can also be added during signal emission.
|
||
|
* In this case, they won't be executed until the next emission occurs.
|
||
|
* @param slot_ The slot to add to the list of slots.
|
||
|
* @return An iterator pointing to the new slot in the list.
|
||
|
*/
|
||
|
iterator_type connect(const slot_base& slot_);
|
||
|
|
||
|
/** Adds a slot at the given position into the list of slots.
|
||
|
* Note that this function does not work during signal emission!
|
||
|
* @param i An iterator indicating the position where @e slot_ should be inserted.
|
||
|
* @param slot_ The slot to add to the list of slots.
|
||
|
* @return An iterator pointing to the new slot in the list.
|
||
|
*/
|
||
|
iterator_type insert(iterator_type i, const slot_base& slot_);
|
||
|
|
||
|
/** Removes the slot at the given position from the list of slots.
|
||
|
* Note that this function does not work during signal emission!
|
||
|
* @param i An iterator pointing to the slot to be removed.
|
||
|
* @return An iterator pointing to the slot in the list after the one removed.
|
||
|
*/
|
||
|
iterator_type erase(iterator_type i);
|
||
|
|
||
|
/** Returns the signal_impl object encapsulating the list of slots.
|
||
|
* @return The signal_impl object encapsulating the list of slots.
|
||
|
*/
|
||
|
internal::signal_impl* impl() const;
|
||
|
|
||
|
/// The signal_impl object encapsulating the slot list.
|
||
|
mutable internal::signal_impl* impl_;
|
||
|
};
|
||
|
|
||
|
} //namespace sigc
|
||
|
|
||
|
#endif /* _SIGC_SIGNAL_BASE_H_ */
|