1 // -*- c++ -*-
2 /*
3  * Copyright 2002, The libsigc++ Development Team
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20 
21 #ifndef _SIGC_SIGNAL_BASE_H_
22 #define _SIGC_SIGNAL_BASE_H_
23 
24 #include <list>
25 #include <sigc++config.h>
26 #include <sigc++/type_traits.h>
27 #include <sigc++/trackable.h>
28 #include <sigc++/functors/slot.h>
29 #include <sigc++/functors/mem_fun.h>
30 
31 namespace sigc
32 {
33 
34 namespace internal
35 {
36 
37 /** Implementation of the signal interface.
38  * signal_impl manages a list of slots. When a slot becomes
39  * invalid (because some referred object dies), notify() is executed.
40  * notify() either calls sweep() directly or defers the execution of
41  * sweep() when the signal is being emitted. sweep() removes all
42  * invalid slot from the list.
43  */
44 struct SIGC_API signal_impl
45 {
46   typedef size_t size_type;
47   typedef std::list<slot_base> slot_list;
48   typedef slot_list::iterator       iterator_type;
49   typedef slot_list::const_iterator const_iterator_type;
50 
51   signal_impl();
52 
53   // only MSVC needs this to guarantee that all new/delete are executed from the DLL module
54 #ifdef SIGC_NEW_DELETE_IN_LIBRARY_ONLY
55   void* operator new(size_t size_);
56   void operator delete(void* p);
57 #endif
58 
59   /// Increments the reference counter.
referencesignal_impl60   inline void reference()
61     { ++ref_count_; }
62 
63   /// Increments the reference and execution counter.
reference_execsignal_impl64   inline void reference_exec()
65     { ++ref_count_; ++exec_count_; }
66 
67   /** Decrements the reference counter.
68    * The object is deleted when the reference counter reaches zero.
69    */
unreferencesignal_impl70   inline void unreference()
71     { if (!(--ref_count_)) delete this; }
72 
73   /** Decrements the reference and execution counter.
74    * Invokes sweep() if the execution counter reaches zero and the
75    * removal of one or more slots has been deferred.
76    */
unreference_execsignal_impl77   inline void unreference_exec()
78     {
79       if (!(--ref_count_)) delete this;
80       else if (!(--exec_count_) && deferred_) sweep();
81     }
82 
83   /** Returns whether the list of slots is empty.
84    * @return @p true if the list of slots is empty.
85    */
emptysignal_impl86   inline bool empty() const
87     { return slots_.empty(); }
88 
89   /// Empties the list of slots.
90   void clear();
91 
92   /** Returns the number of slots in the list.
93    * @return The number of slots in the list.
94    */
95   size_type size() const;
96 
97   /** Adds a slot at the bottom of the list of slots.
98    * @param slot_ The slot to add to the list of slots.
99    * @return An iterator pointing to the new slot in the list.
100    */
101   iterator_type connect(const slot_base& slot_);
102 
103   /** Adds a slot at the given position into the list of slots.
104    * @param i An iterator indicating the position where @p slot_ should be inserted.
105    * @param slot_ The slot to add to the list of slots.
106    * @return An iterator pointing to the new slot in the list.
107    */
108   iterator_type insert(iterator_type i, const slot_base& slot_);
109 
110   /** Removes the slot at the given position from the list of slots.
111    * @param i An iterator pointing to the slot to be removed.
112    * @return An iterator pointing to the slot in the list after the one removed.
113    */
114   iterator_type erase(iterator_type i);
115 
116   /// Removes invalid slots from the list of slots.
117   void sweep();
118 
119   /** Callback that is executed when some slot becomes invalid.
120    * This callback is registered in every slot when inserted into
121    * the list of slots. It is executed when a slot becomes invalid
122    * because of some referred object being destroyed.
123    * It either calls sweep() directly or defers the execution of
124    * sweep() when the signal is being emitted.
125    * @param d The signal object (@p this).
126    */
127   static void* notify(void* d);
128 
129   /** Reference counter.
130    * The object is destroyed when @em ref_count_ reaches zero.
131    */
132   short ref_count_;
133 
134   /** Execution counter.
135    * Indicates whether the signal is being emitted.
136    */
137   short exec_count_;
138 
139   /// Indicates whether the execution of sweep() is being deferred.
140   bool deferred_;
141 
142   /// The list of slots.
143   std::list<slot_base> slots_;
144 };
145 
146 /// Exception safe sweeper for cleaning up invalid slots on the slot list.
147 struct SIGC_API signal_exec
148 {
149   /// The parent sigc::signal_impl object.
150   signal_impl* sig_;
151 
152   /** Increments the reference and execution counter of the parent sigc::signal_impl object.
153    * @param sig The parent sigc::signal_impl object.
154    */
signal_execsignal_exec155   inline signal_exec(const signal_impl* sig)
156     : sig_(const_cast<signal_impl*>(sig) )
157     { sig_->reference_exec(); }
158 
159   /// Decrements the reference and execution counter of the parent sigc::signal_impl object.
~signal_execsignal_exec160   inline ~signal_exec()
161     { sig_->unreference_exec(); }
162 };
163 
164 /** Temporary slot list used during signal emission.
165  *  Through evolution this class is slightly misnamed.  It is now
166  *  an index into the slot_list passed into it.  It simply keeps track
167  *  of where the end of this list was at construction, and pretends that's
168  *  the end of your list.  This way you may connect during emittion without
169  *  inadvertently entering an infinite loop, as well as make other
170  *  modifications to the slot_list at your own risk.
171  */
172 struct temp_slot_list
173 {
174   typedef signal_impl::slot_list slot_list;
175   typedef signal_impl::iterator_type iterator;
176   typedef signal_impl::const_iterator_type const_iterator;
177 
temp_slot_listtemp_slot_list178   temp_slot_list(slot_list &slots) : slots_(slots)
179   {
180     placeholder = slots_.insert(slots_.end(), slot_base());
181   }
182 
~temp_slot_listtemp_slot_list183   ~temp_slot_list()
184   {
185     slots_.erase(placeholder);
186   }
187 
begintemp_slot_list188   iterator begin() { return slots_.begin(); }
endtemp_slot_list189   iterator end() { return placeholder; }
begintemp_slot_list190   const_iterator begin() const { return slots_.begin(); }
endtemp_slot_list191   const_iterator end() const { return placeholder; }
192 
193 private:
194   slot_list &slots_;
195   slot_list::iterator placeholder;
196 };
197 
198 } /* namespace internal */
199 
200 
201 /** @defgroup signal Signals
202  * Use sigc::signal::connect() with sigc::mem_fun() and sigc::ptr_fun() to connect a method or function with a signal.
203  *
204  * @code
205  * signal_clicked.connect( sigc::mem_fun(*this, &MyWindow::on_clicked) );
206  * @endcode
207  *
208  * When the signal is emitted your method will be called.
209  *
210  * signal::connect() returns a connection, which you can later use to disconnect your method.
211  * If the type of your object inherits from sigc::trackable the method is disconnected
212  * automatically when your object is destroyed.
213  *
214  * When signals are copied they share the underlying information,
215  * so you can have a protected/private sigc::signal member and a public accessor method.
216  *
217  * signal and slot objects provide the core functionality of this
218  * library. A slot is a container for an arbitrary functor.
219  * A signal is a list of slots that are executed on emission.
220  * For compile time type safety a list of template arguments
221  * must be provided for the signal template that determines the
222  * parameter list for emission. Functors and closures are converted
223  * into slots implicitely on connection, triggering compiler errors
224  * if the given functor or closure cannot be invoked with the
225  * parameter list of the signal to connect to.
226  */
227 
228 /** Base class for the sigc::signal# templates.
229  * signal_base integrates most of the interface of the derived sigc::signal#
230  * templates. The implementation, however, resides in sigc::internal::signal_impl.
231  * A sigc::internal::signal_impl object is dynamically allocated from signal_base
232  * when first connecting a slot to the signal. This ensures that empty signals
233  * don't waste memory.
234  *
235  * @ingroup signal
236  */
237 struct SIGC_API signal_base : public trackable
238 {
239   typedef size_t size_type;
240 
241   signal_base();
242 
243   signal_base(const signal_base& src);
244 
245   ~signal_base();
246 
247   signal_base& operator = (const signal_base& src);
248 
249   /** Returns whether the list of slots is empty.
250    * @return @p true if the list of slots is empty.
251    */
emptysignal_base252   inline bool empty() const
253     { return (!impl_ || impl_->empty()); }
254 
255   /// Empties the list of slots.
256   void clear();
257 
258   /** Returns the number of slots in the list.
259    * @return The number of slots in the list.
260    */
261   size_type size() const;
262 
263 protected:
264   typedef internal::signal_impl::iterator_type iterator_type;
265 
266   /** Adds a slot at the end of the list of slots.
267    * With connect(), slots can also be added during signal emission.
268    * In this case, they won't be executed until the next emission occurs.
269    * @param slot_ The slot to add to the list of slots.
270    * @return An iterator pointing to the new slot in the list.
271    */
272   iterator_type connect(const slot_base& slot_);
273 
274   /** Adds a slot at the given position into the list of slots.
275    * Note that this function does not work during signal emission!
276    * @param i An iterator indicating the position where @e slot_ should be inserted.
277    * @param slot_ The slot to add to the list of slots.
278    * @return An iterator pointing to the new slot in the list.
279    */
280   iterator_type insert(iterator_type i, const slot_base& slot_);
281 
282   /** Removes the slot at the given position from the list of slots.
283    * Note that this function does not work during signal emission!
284    * @param i An iterator pointing to the slot to be removed.
285    * @return An iterator pointing to the slot in the list after the one removed.
286    */
287   iterator_type erase(iterator_type i);
288 
289   /** Returns the signal_impl object encapsulating the list of slots.
290    * @return The signal_impl object encapsulating the list of slots.
291    */
292   internal::signal_impl* impl() const;
293 
294   /// The signal_impl object encapsulating the slot list.
295   mutable internal::signal_impl* impl_;
296 };
297 
298 } //namespace sigc
299 
300 #endif /* _SIGC_SIGNAL_BASE_H_ */
301