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