2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program 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
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifndef __pbd_signals_h__
21 #define __pbd_signals_h__
24 #include <glibmm/thread.h>
26 #include <boost/signals2.hpp>
27 #include <boost/noncopyable.hpp>
28 #include <boost/bind.hpp>
29 #include <boost/bind/protect.hpp>
31 #include "pbd/event_loop.h"
35 typedef boost::signals2::connection UnscopedConnection;
36 typedef boost::signals2::scoped_connection ScopedConnection;
38 class ScopedConnectionList : public boost::noncopyable
41 ScopedConnectionList();
42 ~ScopedConnectionList ();
44 void add_connection (const UnscopedConnection& c);
45 void drop_connections ();
48 /* this class is not copyable */
49 ScopedConnectionList(const ScopedConnectionList&);
51 /* this lock is shared by all instances of a ScopedConnectionList.
52 We do not want one mutex per list, and since we only need the lock
53 when adding or dropping connections, which are generally occuring
54 in object creation and UI operations, the contention on this
55 lock is low and not of significant consequence. Even though
56 boost::signals2 is thread-safe, this additional list of
57 scoped connections needs to be protected in 2 cases:
59 (1) (unlikely) we make a connection involving a callback on the
60 same object from 2 threads. (wouldn't that just be appalling
63 (2) where we are dropping connections in one thread and adding
67 static Glib::StaticMutex _lock;
69 typedef std::list<ScopedConnection*> ConnectionList;
77 typedef boost::signals2::signal<R()> SignalType;
79 void connect_same_thread (ScopedConnection& c,
80 const typename SignalType::slot_function_type& slot) {
81 c = _signal.connect (slot);
84 void connect_same_thread (ScopedConnectionList& clist,
85 const typename SignalType::slot_function_type& slot) {
86 clist.add_connection (_signal.connect (slot));
89 void connect (ScopedConnectionList& clist,
90 PBD::EventLoop::InvalidationRecord* ir,
91 const typename SignalType::slot_function_type& slot,
92 PBD::EventLoop* event_loop) {
93 clist.add_connection (_signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot)));
96 void connect (ScopedConnection& c,
97 PBD::EventLoop::InvalidationRecord* ir,
98 const typename SignalType::slot_function_type& slot,
99 PBD::EventLoop* event_loop) {
100 c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot));
103 typename SignalType::result_type operator()() {
107 bool empty() const { return _signal.empty(); }
113 template<typename R, typename A, typename C = boost::signals2::optional_last_value<R> >
117 typedef boost::signals2::signal<R(A), C> SignalType;
119 void connect_same_thread (ScopedConnectionList& clist,
120 const typename SignalType::slot_function_type& slot) {
121 clist.add_connection (_signal.connect (slot));
124 void connect_same_thread (ScopedConnection& c,
125 const typename SignalType::slot_function_type& slot) {
126 c = _signal.connect (slot);
129 static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir, A arg) {
130 event_loop->call_slot (ir, boost::bind (f, arg));
133 void connect (ScopedConnectionList& clist,
134 PBD::EventLoop::InvalidationRecord* ir,
135 const typename SignalType::slot_function_type& slot,
136 PBD::EventLoop* event_loop) {
137 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1)));
140 void connect (ScopedConnection& c,
141 PBD::EventLoop::InvalidationRecord* ir,
142 const typename SignalType::slot_function_type& slot,
143 PBD::EventLoop* event_loop) {
144 c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1));
148 typename SignalType::result_type operator()(A arg1) {
149 return _signal (arg1);
152 bool empty() const { return _signal.empty(); }
158 template<typename R, typename A1, typename A2>
162 typedef boost::signals2::signal<R(A1, A2)> SignalType;
164 void connect_same_thread (ScopedConnectionList& clist,
165 const typename SignalType::slot_function_type& slot) {
166 clist.add_connection (_signal.connect (slot));
169 void connect_same_thread (ScopedConnection& c,
170 const typename SignalType::slot_function_type& slot) {
171 c = _signal.connect (slot);
174 static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop,
175 EventLoop::InvalidationRecord* ir,
177 event_loop->call_slot (ir, boost::bind (f, arg1, arg2));
180 void connect (ScopedConnectionList& clist,
181 PBD::EventLoop::InvalidationRecord* ir,
182 const typename SignalType::slot_function_type& slot,
183 PBD::EventLoop* event_loop) {
184 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2)));
187 void connect (ScopedConnection& c,
188 PBD::EventLoop::InvalidationRecord* ir,
189 const typename SignalType::slot_function_type& slot,
190 PBD::EventLoop* event_loop) {
191 c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2));
194 typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
195 return _signal (arg1, arg2);
198 bool empty() const { return _signal.empty(); }
204 template<typename R, typename A1, typename A2, typename A3>
208 typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
210 void connect_same_thread (ScopedConnectionList& clist,
211 const typename SignalType::slot_function_type& slot) {
212 clist.add_connection (_signal.connect (slot));
215 void connect_same_thread (ScopedConnection& c,
216 const typename SignalType::slot_function_type& slot) {
217 c = _signal.connect (slot);
220 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
221 EventLoop::InvalidationRecord* ir,
222 A1 arg1, A2 arg2, A3 arg3) {
223 event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3));
226 void connect (ScopedConnectionList& clist,
227 PBD::EventLoop::InvalidationRecord* ir,
228 const typename SignalType::slot_function_type& slot,
229 PBD::EventLoop* event_loop) {
230 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
233 void connect (ScopedConnection& c,
234 PBD::EventLoop::InvalidationRecord* ir,
235 const typename SignalType::slot_function_type& slot,
236 PBD::EventLoop* event_loop) {
237 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
240 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
241 return _signal (arg1, arg2, arg3);
244 bool empty() const { return _signal.empty(); }
250 template<typename R, typename A1, typename A2, typename A3, typename A4>
254 typedef boost::signals2::signal<R(A1,A2,A3,A4)> SignalType;
256 void connect_same_thread (ScopedConnectionList& clist,
257 const typename SignalType::slot_function_type& slot) {
258 clist.add_connection (_signal.connect (slot));
261 void connect_same_thread (ScopedConnection& c,
262 const typename SignalType::slot_function_type& slot) {
263 c = _signal.connect (slot);
266 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
267 EventLoop::InvalidationRecord* ir,
268 A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
269 event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3, arg4));
272 void connect (ScopedConnectionList& clist,
273 PBD::EventLoop::InvalidationRecord* ir,
274 const typename SignalType::slot_function_type& slot,
275 PBD::EventLoop* event_loop) {
276 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
279 void connect (ScopedConnection& c,
280 PBD::EventLoop::InvalidationRecord* ir,
281 const typename SignalType::slot_function_type& slot,
282 PBD::EventLoop* event_loop) {
283 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
286 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
287 return _signal (arg1, arg2, arg3, arg4);
290 bool empty() const { return _signal.empty(); }
298 #endif /* __pbd_signals_h__ */