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::connection Connection;
37 typedef boost::signals2::scoped_connection ScopedConnection;
39 class ScopedConnectionList : public boost::noncopyable
42 ScopedConnectionList();
43 ~ScopedConnectionList ();
45 void add_connection (const UnscopedConnection& c);
46 void drop_connections ();
49 /* this class is not copyable */
50 ScopedConnectionList(const ScopedConnectionList&);
52 /* this lock is shared by all instances of a ScopedConnectionList.
53 We do not want one mutex per list, and since we only need the lock
54 when adding or dropping connections, which are generally occuring
55 in object creation and UI operations, the contention on this
56 lock is low and not of significant consequence. Even though
57 boost::signals2 is thread-safe, this additional list of
58 scoped connections needs to be protected in 2 cases:
60 (1) (unlikely) we make a connection involving a callback on the
61 same object from 2 threads. (wouldn't that just be appalling
64 (2) where we are dropping connections in one thread and adding
68 static Glib::StaticMutex _lock;
70 typedef std::list<ScopedConnection*> ConnectionList;
78 typedef boost::signals2::signal<R()> SignalType;
80 void connect_same_thread (Connection& c,
81 const typename SignalType::slot_function_type& slot) {
82 c = _signal.connect (slot);
85 void connect_same_thread (ScopedConnectionList& clist,
86 const typename SignalType::slot_function_type& slot) {
87 clist.add_connection (_signal.connect (slot));
90 void connect (ScopedConnectionList& clist,
91 PBD::EventLoop::InvalidationRecord* ir,
92 const typename SignalType::slot_function_type& slot,
93 PBD::EventLoop* event_loop) {
94 clist.add_connection (_signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot)));
97 void connect (Connection& c,
98 PBD::EventLoop::InvalidationRecord* ir,
99 const typename SignalType::slot_function_type& slot,
100 PBD::EventLoop* event_loop) {
101 c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot));
104 typename SignalType::result_type operator()() {
108 bool empty() const { return _signal.empty(); }
114 template<typename R, typename A>
118 typedef boost::signals2::signal<R(A)> SignalType;
120 void connect_same_thread (ScopedConnectionList& clist,
121 const typename SignalType::slot_function_type& slot) {
122 clist.add_connection (_signal.connect (slot));
125 void connect_same_thread (Connection& c,
126 const typename SignalType::slot_function_type& slot) {
127 c = _signal.connect (slot);
130 static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir, A arg) {
131 event_loop->call_slot (ir, boost::bind (f, arg));
134 void connect (ScopedConnectionList& clist,
135 PBD::EventLoop::InvalidationRecord* ir,
136 const typename SignalType::slot_function_type& slot,
137 PBD::EventLoop* event_loop) {
138 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1)));
141 void connect (Connection& c,
142 PBD::EventLoop::InvalidationRecord* ir,
143 const typename SignalType::slot_function_type& slot,
144 PBD::EventLoop* event_loop) {
145 c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1));
149 typename SignalType::result_type operator()(A arg1) {
150 return _signal (arg1);
153 bool empty() const { return _signal.empty(); }
159 template<typename R, typename A1, typename A2>
163 typedef boost::signals2::signal<R(A1, A2)> SignalType;
165 void connect_same_thread (ScopedConnectionList& clist,
166 const typename SignalType::slot_function_type& slot) {
167 clist.add_connection (_signal.connect (slot));
170 void connect_same_thread (Connection& c,
171 const typename SignalType::slot_function_type& slot) {
172 c = _signal.connect (slot);
175 static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop,
176 EventLoop::InvalidationRecord* ir,
178 event_loop->call_slot (ir, boost::bind (f, arg1, arg2));
181 void connect (ScopedConnectionList& clist,
182 PBD::EventLoop::InvalidationRecord* ir,
183 const typename SignalType::slot_function_type& slot,
184 PBD::EventLoop* event_loop) {
185 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2)));
188 void connect (Connection& c,
189 PBD::EventLoop::InvalidationRecord* ir,
190 const typename SignalType::slot_function_type& slot,
191 PBD::EventLoop* event_loop) {
192 c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2));
195 typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
196 return _signal (arg1, arg2);
199 bool empty() const { return _signal.empty(); }
205 template<typename R, typename A1, typename A2, typename A3>
209 typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
211 void connect_same_thread (ScopedConnectionList& clist,
212 const typename SignalType::slot_function_type& slot) {
213 clist.add_connection (_signal.connect (slot));
216 void connect_same_thread (Connection& c,
217 const typename SignalType::slot_function_type& slot) {
218 c = _signal.connect (slot);
221 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
222 EventLoop::InvalidationRecord* ir,
223 A1 arg1, A2 arg2, A3 arg3) {
224 event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3));
227 void connect (ScopedConnectionList& clist,
228 PBD::EventLoop::InvalidationRecord* ir,
229 const typename SignalType::slot_function_type& slot,
230 PBD::EventLoop* event_loop) {
231 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
234 void connect (Connection& c,
235 PBD::EventLoop::InvalidationRecord* ir,
236 const typename SignalType::slot_function_type& slot,
237 PBD::EventLoop* event_loop) {
238 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
241 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
242 return _signal (arg1, arg2, arg3);
245 bool empty() const { return _signal.empty(); }
251 template<typename R, typename A1, typename A2, typename A3, typename A4>
255 typedef boost::signals2::signal<R(A1,A2,A3,A4)> SignalType;
257 void connect_same_thread (ScopedConnectionList& clist,
258 const typename SignalType::slot_function_type& slot) {
259 clist.add_connection (_signal.connect (slot));
262 void connect_same_thread (Connection& c,
263 const typename SignalType::slot_function_type& slot) {
264 c = _signal.connect (slot);
267 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
268 EventLoop::InvalidationRecord* ir,
269 A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
270 event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3, arg4));
273 void connect (ScopedConnectionList& clist,
274 PBD::EventLoop::InvalidationRecord* ir,
275 const typename SignalType::slot_function_type& slot,
276 PBD::EventLoop* event_loop) {
277 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
280 void connect (Connection& c,
281 PBD::EventLoop::InvalidationRecord* ir,
282 const typename SignalType::slot_function_type& slot,
283 PBD::EventLoop* event_loop) {
284 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
287 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
288 return _signal (arg1, arg2, arg3, arg4);
291 bool empty() const { return _signal.empty(); }
299 #endif /* __pbd_signals_h__ */