1 /* 2 * Copyright 2002, The libsigc++ Development Team 3 * 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. 8 * 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. 13 * 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 17 */ 18 19 #ifndef _SIGC_SIGNAL_BASE_H_ 20 #define _SIGC_SIGNAL_BASE_H_ 21 22 #include <cstddef> 23 #include <list> 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> 29 30 /** The libsigc++ namespace. 31 */ 32 namespace sigc 33 { 34 35 namespace internal 36 { 37 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. 44 */ 45 struct SIGC_API signal_impl 46 { 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; 51 52 signal_impl(); 53 54 // only MSVC needs this to guarantee that all new/delete are executed from the DLL module 55 #ifdef SIGC_NEW_DELETE_IN_LIBRARY_ONLY 56 void* operator new(size_t size_); 57 void operator delete(void* p); 58 #endif 59 60 /// Increments the reference counter. referencesignal_impl61 inline void reference() 62 { ++ref_count_; } 63 64 /// Increments the reference and execution counter. reference_execsignal_impl65 inline void reference_exec() 66 { ++ref_count_; ++exec_count_; } 67 68 /** Decrements the reference counter. 69 * The object is deleted when the reference counter reaches zero. 70 */ unreferencesignal_impl71 inline void unreference() 72 { if (!(--ref_count_)) delete this; } 73 74 /** Decrements the reference and execution counter. 75 * Invokes sweep() if the execution counter reaches zero and the 76 * removal of one or more slots has been deferred. 77 */ unreference_execsignal_impl78 inline void unreference_exec() 79 { 80 if (!(--ref_count_)) delete this; 81 else if (!(--exec_count_) && deferred_) sweep(); 82 } 83 84 /** Returns whether the list of slots is empty. 85 * @return @p true if the list of slots is empty. 86 */ emptysignal_impl87 inline bool empty() const 88 { return slots_.empty(); } 89 90 /// Empties the list of slots. 91 void clear(); 92 93 /** Returns the number of slots in the list. 94 * @return The number of slots in the list. 95 */ 96 size_type size() const; 97 98 /** Returns whether all slots in the list are blocked. 99 * @return @p true if all slots are blocked or the list is empty. 100 * 101 * @newin{2,4} 102 */ 103 bool blocked() const; 104 105 /** Sets the blocking state of all slots in the list. 106 * If @e should_block is @p true then the blocking state is set. 107 * Subsequent emissions of the signal don't invoke the functors 108 * contained in the slots until block() with @e should_block = @p false is called. 109 * sigc::slot_base::block() and sigc::slot_base::unblock() can change the 110 * blocking state of individual slots. 111 * @param should_block Indicates whether the blocking state should be set or unset. 112 * 113 * @newin{2,4} 114 */ 115 void block(bool should_block = true); 116 117 /** Adds a slot at the bottom of the list of slots. 118 * @param slot_ The slot to add to the list of slots. 119 * @return An iterator pointing to the new slot in the list. 120 */ 121 iterator_type connect(const slot_base& slot_); 122 123 /** Adds a slot at the given position into the list of slots. 124 * @param i An iterator indicating the position where @p slot_ should be inserted. 125 * @param slot_ The slot to add to the list of slots. 126 * @return An iterator pointing to the new slot in the list. 127 */ 128 iterator_type insert(iterator_type i, const slot_base& slot_); 129 130 /** Removes the slot at the given position from the list of slots. 131 * @param i An iterator pointing to the slot to be removed. 132 * @return An iterator pointing to the slot in the list after the one removed. 133 */ 134 iterator_type erase(iterator_type i); 135 136 /// Removes invalid slots from the list of slots. 137 void sweep(); 138 139 /** Callback that is executed when some slot becomes invalid. 140 * This callback is registered in every slot when inserted into 141 * the list of slots. It is executed when a slot becomes invalid 142 * because of some referred object being destroyed. 143 * It either calls slots_.erase() directly or defers the execution of 144 * erase() to sweep() when the signal is being emitted. 145 * @param d A local structure, created in insert(). 146 */ 147 static void* notify(void* d); 148 149 /** Reference counter. 150 * The object is destroyed when @em ref_count_ reaches zero. 151 */ 152 short ref_count_; 153 154 /** Execution counter. 155 * Indicates whether the signal is being emitted. 156 */ 157 short exec_count_; 158 159 /// Indicates whether the execution of sweep() is being deferred. 160 bool deferred_; 161 162 /// The list of slots. 163 std::list<slot_base> slots_; 164 }; 165 166 /// Exception safe sweeper for cleaning up invalid slots on the slot list. 167 struct SIGC_API signal_exec 168 { 169 /// The parent sigc::signal_impl object. 170 signal_impl* sig_; 171 172 /** Increments the reference and execution counter of the parent sigc::signal_impl object. 173 * @param sig The parent sigc::signal_impl object. 174 */ signal_execsignal_exec175 inline signal_exec(const signal_impl* sig) 176 : sig_(const_cast<signal_impl*>(sig) ) 177 { sig_->reference_exec(); } 178 179 /// Decrements the reference and execution counter of the parent sigc::signal_impl object. ~signal_execsignal_exec180 inline ~signal_exec() 181 { sig_->unreference_exec(); } 182 }; 183 184 /** Temporary slot list used during signal emission. 185 * Through evolution this class is slightly misnamed. It is now 186 * an index into the slot_list passed into it. It simply keeps track 187 * of where the end of this list was at construction, and pretends that's 188 * the end of your list. This way you may connect during emission without 189 * inadvertently entering an infinite loop, as well as make other 190 * modifications to the slot_list at your own risk. 191 */ 192 struct temp_slot_list 193 { 194 typedef signal_impl::slot_list slot_list; 195 typedef signal_impl::iterator_type iterator; 196 typedef signal_impl::const_iterator_type const_iterator; 197 temp_slot_listtemp_slot_list198 temp_slot_list(slot_list &slots) : slots_(slots) 199 { 200 placeholder = slots_.insert(slots_.end(), slot_base()); 201 } 202 ~temp_slot_listtemp_slot_list203 ~temp_slot_list() 204 { 205 slots_.erase(placeholder); 206 } 207 begintemp_slot_list208 iterator begin() { return slots_.begin(); } endtemp_slot_list209 iterator end() { return placeholder; } begintemp_slot_list210 const_iterator begin() const { return slots_.begin(); } endtemp_slot_list211 const_iterator end() const { return placeholder; } 212 213 private: 214 slot_list &slots_; 215 slot_list::iterator placeholder; 216 }; 217 218 } /* namespace internal */ 219 220 221 /** @defgroup signal Signals 222 * Use sigc::signal::connect() with sigc::mem_fun() and sigc::ptr_fun() to connect a method or function with a signal. 223 * 224 * @code 225 * signal_clicked.connect( sigc::mem_fun(*this, &MyWindow::on_clicked) ); 226 * @endcode 227 * 228 * When the signal is emitted your method will be called. 229 * 230 * signal::connect() returns a connection, which you can later use to disconnect your method. 231 * If the type of your object inherits from sigc::trackable the method is disconnected 232 * automatically when your object is destroyed. 233 * 234 * When signals are copied they share the underlying information, 235 * so you can have a protected/private sigc::signal member and a public accessor method. 236 * A sigc::signal is a kind of reference-counting pointer. It's similar to 237 * std::shared_ptr<>, although sigc::signal is restricted to holding a pointer to 238 * a sigc::internal::signal_impl object that contains the implementation of the signal. 239 * 240 * @code 241 * class MyClass 242 * { 243 * public: 244 * typedef sigc::signal<void> MySignalType; 245 * MySignalType get_my_signal() { return m_my_signal; } 246 * private: 247 * MySignalType m_my_signal; 248 * }; 249 * @endcode 250 * 251 * signal and slot objects provide the core functionality of this 252 * library. A slot is a container for an arbitrary functor. 253 * A signal is a list of slots that are executed on emission. 254 * For compile time type safety a list of template arguments 255 * must be provided for the signal template that determines the 256 * parameter list for emission. Functors and closures are converted 257 * into slots implicitly on connection, triggering compiler errors 258 * if the given functor or closure cannot be invoked with the 259 * parameter list of the signal to connect to. 260 * 261 * Almost any functor with the correct signature can be converted to a sigc::slot 262 * and connected to a signal. See @ref slot "Slots" and sigc::signal::connect(). 263 */ 264 265 /** Base class for the sigc::signal# templates. 266 * signal_base integrates most of the interface of the derived sigc::signal# 267 * templates. The implementation, however, resides in sigc::internal::signal_impl. 268 * A sigc::internal::signal_impl object is dynamically allocated from signal_base 269 * when first connecting a slot to the signal. This ensures that empty signals 270 * don't waste memory. 271 * 272 * sigc::internal::signal_impl is reference-counted. When a sigc::signal# object 273 * is copied, the reference count of its sigc::internal::signal_impl object is 274 * incremented. Both sigc::signal# objects then refer to the same 275 * sigc::internal::signal_impl object. 276 * 277 * @ingroup signal 278 */ 279 struct SIGC_API signal_base : public trackable 280 { 281 typedef std::size_t size_type; 282 283 signal_base(); 284 285 signal_base(const signal_base& src); 286 287 ~signal_base(); 288 289 signal_base& operator = (const signal_base& src); 290 291 /** Returns whether the list of slots is empty. 292 * @return @p true if the list of slots is empty. 293 */ emptysignal_base294 inline bool empty() const 295 { return (!impl_ || impl_->empty()); } 296 297 /// Empties the list of slots. 298 void clear(); 299 300 /** Returns the number of slots in the list. 301 * @return The number of slots in the list. 302 */ 303 size_type size() const; 304 305 /** Returns whether all slots in the list are blocked. 306 * @return @p true if all slots are blocked or the list is empty. 307 * 308 * @newin{2,4} 309 */ 310 bool blocked() const; 311 312 /** Sets the blocking state of all slots in the list. 313 * If @e should_block is @p true then the blocking state is set. 314 * Subsequent emissions of the signal don't invoke the functors 315 * contained in the slots until unblock() or block() with 316 * @e should_block = @p false is called. 317 * sigc::slot_base::block() and sigc::slot_base::unblock() can change the 318 * blocking state of individual slots. 319 * @param should_block Indicates whether the blocking state should be set or unset. 320 * 321 * @newin{2,4} 322 */ 323 void block(bool should_block = true); 324 325 /** Unsets the blocking state of all slots in the list. 326 * 327 * @newin{2,4} 328 */ 329 void unblock(); 330 331 protected: 332 typedef internal::signal_impl::iterator_type iterator_type; 333 334 /** Adds a slot at the end of the list of slots. 335 * With connect(), slots can also be added during signal emission. 336 * In this case, they won't be executed until the next emission occurs. 337 * @param slot_ The slot to add to the list of slots. 338 * @return An iterator pointing to the new slot in the list. 339 */ 340 iterator_type connect(const slot_base& slot_); 341 342 /** Adds a slot at the given position into the list of slots. 343 * Note that this function does not work during signal emission! 344 * @param i An iterator indicating the position where @e slot_ should be inserted. 345 * @param slot_ The slot to add to the list of slots. 346 * @return An iterator pointing to the new slot in the list. 347 */ 348 iterator_type insert(iterator_type i, const slot_base& slot_); 349 350 /** Removes the slot at the given position from the list of slots. 351 * Note that this function does not work during signal emission! 352 * @param i An iterator pointing to the slot to be removed. 353 * @return An iterator pointing to the slot in the list after the one removed. 354 */ 355 iterator_type erase(iterator_type i); 356 357 /** Returns the signal_impl object encapsulating the list of slots. 358 * @return The signal_impl object encapsulating the list of slots. 359 */ 360 internal::signal_impl* impl() const; 361 362 /// The signal_impl object encapsulating the slot list. 363 mutable internal::signal_impl* impl_; 364 }; 365 366 } //namespace sigc 367 368 #endif /* _SIGC_SIGNAL_BASE_H_ */ 369