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