2 * Copyright 2002, The libsigc++ Development Team
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #ifndef _SIGC_SIGNAL_BASE_H_
20 #define _SIGC_SIGNAL_BASE_H_
24 #include <sigc++config.h>
25 #include <sigc++/type_traits.h>
26 #include <sigc++/trackable.h>
27 #include <sigc++/functors/slot.h>
28 #include <sigc++/functors/mem_fun.h>
30 /** The libsigc++ namespace.
38 /** Implementation of the signal interface.
39 * signal_impl manages a list of slots. When a slot becomes
40 * invalid (because some referred object dies), notify() is executed.
41 * notify() either calls slots_.erase() directly or defers the execution of
42 * erase() to sweep() when the signal is being emitted. sweep() removes all
43 * invalid slots from the list.
45 struct SIGC_API signal_impl
47 typedef std::size_t size_type;
48 typedef std::list<slot_base> slot_list;
49 typedef slot_list::iterator iterator_type;
50 typedef slot_list::const_iterator const_iterator_type;
54 signal_impl(const signal_impl& src) = delete;
55 signal_impl& operator=(const signal_impl& src) = delete;
57 signal_impl(signal_impl&& src) = delete;
58 signal_impl& operator=(signal_impl&& src) = delete;
60 // only MSVC needs this to guarantee that all new/delete are executed from the DLL module
61 #ifdef SIGC_NEW_DELETE_IN_LIBRARY_ONLY
62 void* operator new(size_t size_);
63 void operator delete(void* p);
66 /// Increments the reference counter.
67 inline void reference() noexcept
70 /// Increments the reference and execution counter.
71 inline void reference_exec() noexcept
72 { ++ref_count_; ++exec_count_; }
74 /** Decrements the reference counter.
75 * The object is deleted when the reference counter reaches zero.
77 inline void unreference()
78 { if (!(--ref_count_)) delete this; }
80 /** Decrements the reference and execution counter.
81 * Invokes sweep() if the execution counter reaches zero and the
82 * removal of one or more slots has been deferred.
84 inline void unreference_exec()
86 if (!(--ref_count_)) delete this;
87 else if (!(--exec_count_) && deferred_) sweep();
90 /** Returns whether the list of slots is empty.
91 * @return @p true if the list of slots is empty.
93 inline bool empty() const noexcept
94 { return slots_.empty(); }
96 /// Empties the list of slots.
99 /** Returns the number of slots in the list.
100 * @return The number of slots in the list.
102 size_type size() const noexcept;
104 /** Returns whether all slots in the list are blocked.
105 * @return @p true if all slots are blocked or the list is empty.
109 bool blocked() const noexcept;
111 /** Sets the blocking state of all slots in the list.
112 * If @e should_block is @p true then the blocking state is set.
113 * Subsequent emissions of the signal don't invoke the functors
114 * contained in the slots until block() with @e should_block = @p false is called.
115 * sigc::slot_base::block() and sigc::slot_base::unblock() can change the
116 * blocking state of individual slots.
117 * @param should_block Indicates whether the blocking state should be set or unset.
121 void block(bool should_block = true) noexcept;
123 /** Adds a slot at the bottom of the list of slots.
124 * @param slot_ The slot to add to the list of slots.
125 * @return An iterator pointing to the new slot in the list.
127 iterator_type connect(const slot_base& slot_);
129 /** Adds a slot at the bottom of the list of slots.
130 * @param slot_ The slot to add to the list of slots.
131 * @return An iterator pointing to the new slot in the list.
135 iterator_type connect(slot_base&& slot_);
137 /** Adds a slot at the given position into the list of slots.
138 * @param i An iterator indicating the position where @p slot_ should be inserted.
139 * @param slot_ The slot to add to the list of slots.
140 * @return An iterator pointing to the new slot in the list.
142 iterator_type insert(iterator_type i, const slot_base& slot_);
144 /** Adds a slot at the given position into the list of slots.
145 * @param i An iterator indicating the position where @p slot_ should be inserted.
146 * @param slot_ The slot to add to the list of slots.
147 * @return An iterator pointing to the new slot in the list.
151 iterator_type insert(iterator_type i, slot_base&& slot_);
153 /** Removes the slot at the given position from the list of slots.
154 * @param i An iterator pointing to the slot to be removed.
155 * @return An iterator pointing to the slot in the list after the one removed.
157 iterator_type erase(iterator_type i);
159 /// Removes invalid slots from the list of slots.
162 /** Callback that is executed when some slot becomes invalid.
163 * This callback is registered in every slot when inserted into
164 * the list of slots. It is executed when a slot becomes invalid
165 * because of some referred object being destroyed.
166 * It either calls slots_.erase() directly or defers the execution of
167 * erase() to sweep() when the signal is being emitted.
168 * @param d A local structure, created in insert().
170 static void* notify(void* d);
172 /** Reference counter.
173 * The object is destroyed when @em ref_count_ reaches zero.
177 /** Execution counter.
178 * Indicates whether the signal is being emitted.
182 /// Indicates whether the execution of sweep() is being deferred.
185 /// The list of slots.
186 std::list<slot_base> slots_;
189 /// Exception safe sweeper for cleaning up invalid slots on the slot list.
190 struct SIGC_API signal_exec
192 /// The parent sigc::signal_impl object.
195 /** Increments the reference and execution counter of the parent sigc::signal_impl object.
196 * @param sig The parent sigc::signal_impl object.
198 inline signal_exec(const signal_impl* sig) noexcept
199 : sig_(const_cast<signal_impl*>(sig) )
200 { sig_->reference_exec(); }
202 /// Decrements the reference and execution counter of the parent sigc::signal_impl object.
203 inline ~signal_exec()
204 { sig_->unreference_exec(); }
207 /** Temporary slot list used during signal emission.
208 * Through evolution this class is slightly misnamed. It is now
209 * an index into the slot_list passed into it. It simply keeps track
210 * of where the end of this list was at construction, and pretends that's
211 * the end of your list. This way you may connect during emission without
212 * inadvertently entering an infinite loop, as well as make other
213 * modifications to the slot_list at your own risk.
215 struct temp_slot_list
217 typedef signal_impl::slot_list slot_list;
218 typedef signal_impl::iterator_type iterator;
219 typedef signal_impl::const_iterator_type const_iterator;
221 temp_slot_list(slot_list &slots) : slots_(slots)
223 placeholder = slots_.insert(slots_.end(), slot_base());
228 slots_.erase(placeholder);
231 iterator begin() { return slots_.begin(); }
232 iterator end() { return placeholder; }
233 const_iterator begin() const { return slots_.begin(); }
234 const_iterator end() const { return placeholder; }
238 slot_list::iterator placeholder;
241 } /* namespace internal */
244 /** @defgroup signal Signals
245 * Use sigc::signal::connect() with sigc::mem_fun() and sigc::ptr_fun() to connect a method or function with a signal.
248 * signal_clicked.connect( sigc::mem_fun(*this, &MyWindow::on_clicked) );
251 * When the signal is emitted your method will be called.
253 * signal::connect() returns a connection, which you can later use to disconnect your method.
254 * If the type of your object inherits from sigc::trackable the method is disconnected
255 * automatically when your object is destroyed.
257 * When signals are copied they share the underlying information,
258 * so you can have a protected/private sigc::signal member and a public accessor method.
259 * A sigc::signal is a kind of reference-counting pointer. It's similar to
260 * std::shared_ptr<>, although sigc::signal is restricted to holding a pointer to
261 * a sigc::internal::signal_impl object that contains the implementation of the signal.
267 * typedef sigc::signal<void> MySignalType;
268 * MySignalType get_my_signal() { return m_my_signal; }
270 * MySignalType m_my_signal;
274 * signal and slot objects provide the core functionality of this
275 * library. A slot is a container for an arbitrary functor.
276 * A signal is a list of slots that are executed on emission.
277 * For compile time type safety a list of template arguments
278 * must be provided for the signal template that determines the
279 * parameter list for emission. Functors and closures are converted
280 * into slots implicitly on connection, triggering compiler errors
281 * if the given functor or closure cannot be invoked with the
282 * parameter list of the signal to connect to.
284 * Almost any functor with the correct signature can be converted to a sigc::slot
285 * and connected to a signal. See @ref slot "Slots" and sigc::signal::connect().
288 /** Base class for the sigc::signal# templates.
289 * signal_base integrates most of the interface of the derived sigc::signal#
290 * templates. The implementation, however, resides in sigc::internal::signal_impl.
291 * A sigc::internal::signal_impl object is dynamically allocated from signal_base
292 * when first connecting a slot to the signal. This ensures that empty signals
293 * don't waste memory.
295 * sigc::internal::signal_impl is reference-counted. When a sigc::signal# object
296 * is copied, the reference count of its sigc::internal::signal_impl object is
297 * incremented. Both sigc::signal# objects then refer to the same
298 * sigc::internal::signal_impl object.
300 * Deleting the signal during emission, e.g. from one of its slots, may result
301 * in memory leaks. This drawback is fixed in version 3 of libsigc++.
302 * A workaround is to make a copy of the signal during the emission:
304 * sigc::signal<...> sig2(*p_sig);
307 * This is not very costly. A sigc::signal<> is not much more than a pointer to
308 * a sigc::internal::signal_impl instance, which is not copied.
312 struct SIGC_API signal_base : public trackable
314 typedef std::size_t size_type;
316 signal_base() noexcept;
318 signal_base(const signal_base& src) noexcept;
320 signal_base(signal_base&& src);
324 signal_base& operator=(const signal_base& src);
326 signal_base& operator=(signal_base&& src);
328 /** Returns whether the list of slots is empty.
329 * @return @p true if the list of slots is empty.
331 inline bool empty() const noexcept
332 { return (!impl_ || impl_->empty()); }
334 /// Empties the list of slots.
337 /** Returns the number of slots in the list.
338 * @return The number of slots in the list.
340 size_type size() const noexcept;
342 /** Returns whether all slots in the list are blocked.
343 * @return @p true if all slots are blocked or the list is empty.
347 bool blocked() const noexcept;
349 /** Sets the blocking state of all slots in the list.
350 * If @e should_block is @p true then the blocking state is set.
351 * Subsequent emissions of the signal don't invoke the functors
352 * contained in the slots until unblock() or block() with
353 * @e should_block = @p false is called.
354 * sigc::slot_base::block() and sigc::slot_base::unblock() can change the
355 * blocking state of individual slots.
356 * @param should_block Indicates whether the blocking state should be set or unset.
360 void block(bool should_block = true) noexcept;
362 /** Unsets the blocking state of all slots in the list.
366 void unblock() noexcept;
369 typedef internal::signal_impl::iterator_type iterator_type;
371 /** Adds a slot at the end of the list of slots.
372 * With connect(), slots can also be added during signal emission.
373 * In this case, they won't be executed until the next emission occurs.
374 * @param slot_ The slot to add to the list of slots.
375 * @return An iterator pointing to the new slot in the list.
377 iterator_type connect(const slot_base& slot_);
379 /** Adds a slot at the end of the list of slots.
380 * With connect(), slots can also be added during signal emission.
381 * In this case, they won't be executed until the next emission occurs.
382 * @param slot_ The slot to add to the list of slots.
383 * @return An iterator pointing to the new slot in the list.
387 iterator_type connect(slot_base&& slot_);
389 /** Adds a slot at the given position into the list of slots.
390 * Note that this function does not work during signal emission!
391 * @param i An iterator indicating the position where @e slot_ should be inserted.
392 * @param slot_ The slot to add to the list of slots.
393 * @return An iterator pointing to the new slot in the list.
395 iterator_type insert(iterator_type i, const slot_base& slot_);
397 /** Adds a slot at the given position into the list of slots.
398 * Note that this function does not work during signal emission!
399 * @param i An iterator indicating the position where @e slot_ should be inserted.
400 * @param slot_ The slot to add to the list of slots.
401 * @return An iterator pointing to the new slot in the list.
405 iterator_type insert(iterator_type i, slot_base&& slot_);
407 /** Removes the slot at the given position from the list of slots.
408 * Note that this function does not work during signal emission!
409 * @param i An iterator pointing to the slot to be removed.
410 * @return An iterator pointing to the slot in the list after the one removed.
412 iterator_type erase(iterator_type i);
414 /** Returns the signal_impl object encapsulating the list of slots.
415 * @return The signal_impl object encapsulating the list of slots.
417 internal::signal_impl* impl() const;
419 /// The signal_impl object encapsulating the slot list.
420 mutable internal::signal_impl* impl_;
425 #endif /* _SIGC_SIGNAL_BASE_H_ */