]> git.tdb.fi Git - ext/sigc++-2.0.git/blob - sigc++/functors/slot_base.h
Import libsigc++ 2.10.8 sources
[ext/sigc++-2.0.git] / sigc++ / functors / slot_base.h
1 /*
2  * Copyright 2003, 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_SLOT_BASE_HPP_
20 #define _SIGC_SLOT_BASE_HPP_
21
22 #include <sigc++config.h>
23 #include <sigc++/trackable.h>
24 #include <sigc++/functors/functor_trait.h>
25
26 namespace sigc
27 {
28
29 namespace internal {
30
31 typedef void* (*hook)(void*);
32
33 /** Internal representation of a slot.
34  * Derivations of this class can be considered as a link
35  * between a slot and the functor that the slot should
36  * execute in operator(). This link is needed because in
37  * libsigc++ the slot doesn't necessarily have exactly the
38  * same function signature as the functor, thus allowing for
39  * implicit conversions.
40  *
41  * The base class slot_rep serves the purpose to
42  * - form a common pointer type (slot_rep*),
43  * - offer the possibility to create duplicates (dup()),
44  * - offer a notification callback (notify()),
45  * - implement some of slot_base's interface that depends
46  *   on the notification callback, i.e.
47  *   -# the possibility to set a single parent with a callback
48  *      (set_parent()) that is executed from notify(),
49  *   -# a generic function pointer, call_, that is simply
50  *      set to zero in notify() to invalidate the slot.
51  *
52  * slot_rep inherits trackable so that connection objects can
53  * refer to the slot and are notified when the slot is destroyed.
54  */
55 struct SIGC_API slot_rep : public trackable
56 {
57   slot_rep(const slot_rep& src) = delete;
58   slot_rep& operator=(const slot_rep& src) = delete;
59
60   slot_rep(slot_rep&& src) = delete;
61   slot_rep& operator=(slot_rep&& src) = delete;
62
63   /* NB: Instead of slot_rep we could inherit slot_base from trackable.
64    * However, a simple benchmark seems to indicate that this slows
65    * down dereferencing of slot list iterators. Martin. */
66
67   /// Callback that invokes the contained functor.
68   /* This can't be a virtual function since number of arguments
69    * must be flexible. We use function pointers to slot_call::call_it()
70    * instead. call_ is set to zero to indicate that the slot is invalid.
71    */
72   hook call_;
73
74   /// Callback that detaches the slot_rep object from referred trackables and destroys it.
75   /* This could be a replaced by a virtual dtor. However since this struct is
76    * crucual for the efficiency of the whole library we want to avoid this.
77    */
78   hook destroy_;
79
80   /** Callback that makes a deep copy of the slot_rep object.
81    * @return A deep copy of the slot_rep object.
82    */
83   hook dup_;
84
85   /** Callback of parent_. */
86   hook cleanup_;
87
88   /** Parent object whose callback cleanup_ is executed on notification. */
89   void* parent_;
90
91   inline slot_rep(hook call__, hook destroy__, hook dup__) noexcept
92     : call_(call__), destroy_(destroy__), dup_(dup__), cleanup_(nullptr), parent_(nullptr) {}
93
94   inline ~slot_rep()
95     { destroy(); }
96
97   // only MSVC needs this to guarantee that all new/delete are executed from the DLL module
98 #ifdef SIGC_NEW_DELETE_IN_LIBRARY_ONLY
99   void* operator new(size_t size_);
100   void operator delete(void* p);
101 #endif
102
103   /** Destroys the slot_rep object (but doesn't delete it).
104    */
105   inline void destroy()
106     { if (destroy_) (*destroy_)(this); }
107
108   /** Makes a deep copy of the slot_rep object.
109    * @return A deep copy of the slot_rep object.
110    */
111   inline slot_rep* dup() const
112     { return reinterpret_cast<slot_rep*>((*dup_)(const_cast<slot_rep*>(this))); }
113
114   /** Set the parent with a callback.
115    * slots have one parent exclusively.
116    * @param parent The new parent.
117    * @param cleanup The callback to execute from notify().
118    */
119   inline void set_parent(void* parent, hook cleanup) noexcept
120     {
121       parent_ = parent;
122       cleanup_ = cleanup;
123     }
124
125   /// Invalidates the slot and executes the parent's cleanup callback.
126   void disconnect();
127
128   /** Callback that invalidates the slot.
129    * This callback is registered in every object of a trackable
130    * inherited type that is referred by this slot_rep object.
131    * It is executed when the slot becomes invalid because of some
132    * referred object dying.
133    * @param data The slot_rep object that is becoming invalid (@p this).
134    */
135   static void* notify(void* data);
136 };
137
138 /** Functor used to add a dependency to a trackable.
139  * Consequently slot_rep::notify() gets executed when the
140  * trackable is destroyed or overwritten.
141  */
142 struct SIGC_API slot_do_bind
143 {
144   /** The slot_rep object trackables should notify on destruction. */
145   slot_rep* rep_;
146
147   /** Construct a slot_do_bind functor.
148    * @param rep The slot_rep object trackables should notify on destruction.
149    */
150   inline slot_do_bind(slot_rep* rep) noexcept : rep_(rep) {}
151
152   /** Adds a dependency to @p t.
153    * @param t The trackable object to add a callback to.
154    */
155   inline void operator()(const trackable* t) const
156     { t->add_destroy_notify_callback(rep_, &slot_rep::notify); }
157 };
158
159 /// Functor used to remove a dependency from a trackable.
160 struct SIGC_API slot_do_unbind
161 {
162   /** The slot_rep object trackables don't need to notify on destruction any more. */
163   slot_rep* rep_;
164
165   /** Construct a slot_do_unbind functor.
166    * @param rep The slot_rep object trackables don't need to notify on destruction any more.
167    */
168   inline slot_do_unbind(slot_rep* rep) noexcept : rep_(rep) {}
169
170   /** Removes a dependency from @p t.
171    * @param t The trackable object to remove the callback from.
172    */
173   inline void operator()(const trackable* t) const
174     { t->remove_destroy_notify_callback(rep_); }
175 };
176
177 } //namespace internal
178
179
180 /** @defgroup slot Slots
181  * Slots are type-safe representations of callback methods and functions.
182  * A slot can be constructed from any function object or function, regardless of
183  * whether it is a global function, a member method, static, or virtual.
184  *
185  * @section slots-creating Creating Slots
186  *
187  * Use the sigc::mem_fun() or sigc::ptr_fun() template functions to get a sigc::slot, like so:
188  * @code
189  * sigc::slot<void, int> sl = sigc::mem_fun(someobj, &SomeClass::somemethod);
190  * @endcode
191  * or
192  * @code
193  * sigc::slot<void, int> sl = sigc::ptr_fun(&somefunction);
194  * @endcode
195  * or, in gtkmm,
196  * @code
197  * m_Button.signal_clicked().connect( sigc::mem_fun(*this, &MyWindow::on_button_clicked) );
198  * @endcode
199  *
200  * The compiler will complain if SomeClass::somemethod, etc. have the wrong signature.
201  *
202  * You can also pass slots as method parameters where you might normally pass a function pointer.
203  *
204  * @section slots-auto-disconnect Member Methods and Automatic Disconnection
205  *
206  * See @ref mem_fun "sigc::mem_fun()" about deriving from sigc::trackable to prevent member
207  * methods from being called after the instance has been destroyed.
208  *
209  * @section slots-auto auto
210  *
211  * sigc::mem_fun() and sigc::ptr_fun() return functors, but those functors are
212  * not slots.
213  * @code
214  * sigc::slot<void, int> sl = sigc::mem_fun(someobj, &SomeClass::somemethod);
215  * @endcode
216  * is not equivalent to
217  * @code
218  * auto sl = sigc::mem_fun(someobj, &SomeClass::somemethod); // Not a slot!
219  * @endcode
220  *
221  * If you don't explicitly use a sigc::slot then the slot could call a method
222  * on an instance after it has been destroyed even if the method is in a class
223  * that derives from sigc::trackable.
224  *
225  * @section slots-with-lambdas C++ Lambdas
226  *
227  * A C++11 lambda expression is a functor (function object). It is automatically
228  * wrapped in a slot, if it is connected to a signal.
229  * @code
230  * auto on_response = [&someobj] (int response_id)
231  *   {
232  *     someobj.somemethod(response_id);
233  *     somefunction(response_id);
234  *   };
235  * m_Dialog.signal_response().connect(on_response);
236  * @endcode
237  *
238  * If you connect a C++11 lambda expression or a std::function<> instance to
239  * a signal or assign it to a slot,
240  * - With libsigc++ versions before 2.6, if the return type is not void,
241      you must use the #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE macro,
242  * - if your functor contains references to sigc::trackable derived objects,
243  *   those objects will not be tracked, unless you also use sigc::track_obj().
244  *
245  * @ingroup sigcfunctors
246  */
247
248 /** Base type for slots.
249  * slot_base integrates most of the interface of the derived
250  * sigc::slot templates. slots
251  * can be connected to signals, be disconnected at some later point
252  * (disconnect()) and temporarily be blocked (block(), unblock()).
253  * The validity of a slot can be tested with empty().
254  *
255  * The internal representation of a sigc::internal::slot_rep derived
256  * type is built from slot_base's derivations. set_parent() is used to
257  * register a notification callback that is executed when the slot gets
258  * invalid. add_destroy_notify_callback() is used by connection objects
259  * to add a notification callback that is executed on destruction.
260  *
261  * @ingroup slot
262  */
263 class SIGC_API slot_base : public functor_base
264 {
265   typedef internal::slot_rep rep_type;
266
267   // Move operations are not declared noexcept because
268   // 1. they may copy instead of move
269   // 2. when they don't copy, they call src.rep_->notify_callbacks(), which
270   //    may throw an exception.
271 public:
272   /// Constructs an empty slot.
273   slot_base() noexcept;
274
275   /** Constructs a slot from an existing slot_rep object.
276    * @param rep The slot_rep object this slot should contain.
277    */
278   explicit slot_base(rep_type* rep) noexcept;
279
280   /** Constructs a slot, copying an existing one.
281    * @param src The existing slot to copy.
282    */
283   slot_base(const slot_base& src);
284
285   /** Constructs a slot, moving an existing one.
286    * If @p src is connected to a parent (e.g. a signal), it is copied, not moved.
287    * @param src The existing slot to move or copy.
288    */
289   slot_base(slot_base&& src);
290
291   ~slot_base();
292
293   /** Tests whether a slot is null, because the default constructor was used.
294    * Test a slot for null like so:
295    * @code
296    * if(slot)
297    *  do_something()
298    * @endcode
299    */
300   explicit operator bool() const noexcept;
301
302   /** Sets the parent of this slot.
303    * This function is used by signals to register a notification callback.
304    * This notification callback is executed when the slot becomes invalid
305    * because of some referred object dying.
306    * @param parent The new parent.
307    * @param cleanup The notification callback.
308    */
309   void set_parent(void* parent, void* (*cleanup)(void*)) const noexcept;
310
311   typedef trackable::func_destroy_notify func_destroy_notify;
312   /** Add a callback that is executed (notified) when the slot is detroyed.
313    * This function is used internally by connection objects.
314    * @param data Passed into func upon notification.
315    * @param func Callback executed upon destruction of the object.
316    */
317   void add_destroy_notify_callback(void* data, func_destroy_notify func) const;
318
319   /** Remove a callback previously installed with add_destroy_notify_callback().
320    * The callback is not executed.
321    * @param data Parameter passed into previous call to add_destroy_notify_callback().
322    */
323   void remove_destroy_notify_callback(void* data) const;
324
325   /** Returns whether the slot is invalid.
326    * @return @p true if the slot is invalid (empty).
327    */
328   inline bool empty() const noexcept
329     { return (!rep_ || !rep_->call_); }
330
331   /** Returns whether the slot is blocked.
332    * @return @p true if the slot is blocked.
333    */
334   inline bool blocked() const noexcept
335     { return blocked_; }
336     
337   /** Sets the blocking state.
338    * If @e should_block is @p true then the blocking state is set.
339    * Subsequent calls to slot::operator()() don't invoke the functor
340    * contained by this slot until unblock() or block() with
341    * @e should_block = @p false is called.
342    * @param should_block Indicates whether the blocking state should be set or unset.
343    * @return @p true if the slot was in blocking state before.
344    */
345   bool block(bool should_block = true) noexcept;
346
347   /** Unsets the blocking state.
348    * @return @p true if the slot was in blocking state before.
349    */
350   bool unblock() noexcept;
351
352   /** Disconnects the slot.
353    * Invalidates the slot and notifies the parent.
354    */
355   void disconnect();
356
357 //The Tru64 and Solaris Forte 5.5 compilers needs this operator=() to be public. I'm not sure why, or why it needs to be protected usually. murrayc.
358 //See bug #168265. 
359 //protected:
360   /** Overrides this slot, making a copy from another slot.
361    * @param src The slot from which to make a copy.
362    * @return @p this.
363    */
364   slot_base& operator=(const slot_base& src);
365
366   /** Overrides this slot, making a move from another slot.
367    * If @p src is connected to a parent (e.g. a signal), it is copied, not moved.
368    * @param src The slot from which to move or copy.
369    * @return @p this.
370    */
371   slot_base& operator=(slot_base&& src);
372
373 public: // public to avoid template friend declarations
374   /** Typed slot_rep object that contains a functor. */
375   mutable rep_type *rep_;
376
377   /** Indicates whether the slot is blocked. */
378   bool blocked_;
379
380 private:
381   void delete_rep_with_check();
382 };
383
384 } //namespace sigc
385
386 #endif //_SIGC_SLOT_BASE_HPP_
387