1 // -*- c++ -*-
2 /*
3  * Copyright 2003, 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 #include <sigc++/functors/slot_base.h>
22 
23 namespace sigc
24 {
25 
26 namespace internal {
27 
28 // only MSVC needs this to guarantee that all new/delete are executed from the DLL module
29 #ifdef SIGC_NEW_DELETE_IN_LIBRARY_ONLY
operator new(size_t size_)30 void* slot_rep::operator new(size_t size_)
31 {
32   return malloc(size_);
33 }
34 
operator delete(void * p)35 void slot_rep::operator delete(void* p)
36 {
37   free(p);
38 }
39 #endif
40 
disconnect()41 void slot_rep::disconnect()
42 {
43   if (parent_)
44   {
45     call_ = 0;          // Invalidate the slot.
46                         // _Must_ be done here because parent_ might defer the actual
47                         // destruction of the slot_rep and try to invoke it before that point.
48     void* data_ = parent_;
49     parent_ = 0;        // Just a precaution.
50     (cleanup_)(data_);  // Notify the parent (might lead to destruction of this!).
51   }
52   else
53     call_ = 0;
54 }
55 
56 //static
notify(void * data)57 void* slot_rep::notify(void* data)
58 {
59   slot_rep* self_ = reinterpret_cast<slot_rep*>(data);
60 
61   self_->call_ = 0; // Invalidate the slot.
62   self_->destroy(); // Detach the stored functor from the other referred trackables and destroy it.
63   self_->disconnect(); // Disconnect the slot (might lead to deletion of self_!).
64 
65   return 0;
66 }
67 
68 } // namespace internal
69 
slot_base()70 slot_base::slot_base()
71 : rep_(0),
72   blocked_(false)
73 {}
74 
slot_base(rep_type * rep)75 slot_base::slot_base(rep_type* rep)
76 : rep_(rep),
77   blocked_(false)
78 {}
79 
slot_base(const slot_base & src)80 slot_base::slot_base(const slot_base& src)
81 : rep_(0),
82   blocked_(src.blocked_)
83 {
84   if (src.rep_)
85   {
86     //Check call_ so we can ignore invalidated slots.
87     //Otherwise, destroyed bound reference parameters (whose destruction caused the slot's invalidation) may be used during dup().
88     //Note: I'd prefer to check somewhere during dup(). murrayc.
89     if (src.rep_->call_)
90       rep_ = src.rep_->dup();
91     else
92     {
93       *this = slot_base(); //Return the default invalid slot.
94     }
95   }
96 }
97 
~slot_base()98 slot_base::~slot_base()
99 {
100   if (rep_)
101     delete rep_;
102 }
103 
operator bool() const104 slot_base::operator bool() const
105 {
106   return rep_ != 0;
107 }
108 
operator =(const slot_base & src)109 slot_base& slot_base::operator=(const slot_base& src)
110 {
111   if (src.rep_ == rep_) return *this;
112 
113   if (src.empty())
114   {
115     disconnect();
116     return *this;
117   }
118 
119   internal::slot_rep* new_rep_ = src.rep_->dup();
120 
121   if (rep_)               // Silently exchange the slot_rep.
122   {
123     new_rep_->set_parent(rep_->parent_, rep_->cleanup_);
124     delete rep_;
125   }
126 
127   rep_ = new_rep_;
128 
129   return *this;
130 }
131 
set_parent(void * parent,void * (* cleanup)(void *)) const132 void slot_base::set_parent(void* parent, void* (*cleanup)(void*)) const
133 {
134   if (rep_)
135     rep_->set_parent(parent, cleanup);
136 }
137 
add_destroy_notify_callback(void * data,func_destroy_notify func) const138 void slot_base::add_destroy_notify_callback(void* data, func_destroy_notify func) const
139 {
140   if (rep_)
141     rep_->add_destroy_notify_callback(data, func);
142 }
143 
remove_destroy_notify_callback(void * data) const144 void slot_base::remove_destroy_notify_callback(void* data) const
145 {
146   if (rep_)
147     rep_->remove_destroy_notify_callback(data);
148 }
149 
block(bool should_block)150 bool slot_base::block(bool should_block)
151 {
152   bool old = blocked_;
153   blocked_ = should_block;
154   return old;
155 }
156 
unblock()157 bool slot_base::unblock()
158 {
159   return block(false);
160 }
161 
disconnect()162 void slot_base::disconnect()
163 {
164   if (rep_)
165     rep_->disconnect();
166 }
167 
168 
169 /*bool slot_base::empty() const // having this function not inline is killing performance !!!
170 {
171   if (rep_ && !rep_->call_)
172     {
173       delete rep_;        // This is not strictly necessary here. I'm convinced that it is
174       rep_ = 0;           // safe to wait for the destructor to delete the slot_rep. Martin.
175     }
176   return (rep_ == 0);
177 }*/
178 
179 } //namespace sigc
180