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) {
94 ir->event_loop = event_loop;
96 clist.add_connection (_signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot)));
99 void connect (ScopedConnection& c,
100 PBD::EventLoop::InvalidationRecord* ir,
101 const typename SignalType::slot_function_type& slot,
102 PBD::EventLoop* event_loop) {
104 ir->event_loop = event_loop;
106 c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot));
109 typename SignalType::result_type operator()() {
113 bool empty() const { return _signal.empty(); }
119 template<typename R, typename A, typename C = boost::signals2::optional_last_value<R> >
123 typedef boost::signals2::signal<R(A), C> SignalType;
125 void connect_same_thread (ScopedConnectionList& clist,
126 const typename SignalType::slot_function_type& slot) {
127 clist.add_connection (_signal.connect (slot));
130 void connect_same_thread (ScopedConnection& c,
131 const typename SignalType::slot_function_type& slot) {
132 c = _signal.connect (slot);
135 static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir, A arg) {
136 event_loop->call_slot (ir, boost::bind (f, arg));
139 void connect (ScopedConnectionList& clist,
140 PBD::EventLoop::InvalidationRecord* ir,
141 const typename SignalType::slot_function_type& slot,
142 PBD::EventLoop* event_loop) {
144 ir->event_loop = event_loop;
146 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1)));
149 void connect (ScopedConnection& c,
150 PBD::EventLoop::InvalidationRecord* ir,
151 const typename SignalType::slot_function_type& slot,
152 PBD::EventLoop* event_loop) {
154 ir->event_loop = event_loop;
156 c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1));
160 typename SignalType::result_type operator()(A arg1) {
161 return _signal (arg1);
164 bool empty() const { return _signal.empty(); }
170 template<typename R, typename A1, typename A2>
174 typedef boost::signals2::signal<R(A1, A2)> SignalType;
176 void connect_same_thread (ScopedConnectionList& clist,
177 const typename SignalType::slot_function_type& slot) {
178 clist.add_connection (_signal.connect (slot));
181 void connect_same_thread (ScopedConnection& c,
182 const typename SignalType::slot_function_type& slot) {
183 c = _signal.connect (slot);
186 static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop,
187 EventLoop::InvalidationRecord* ir,
189 event_loop->call_slot (ir, boost::bind (f, arg1, arg2));
192 void connect (ScopedConnectionList& clist,
193 PBD::EventLoop::InvalidationRecord* ir,
194 const typename SignalType::slot_function_type& slot,
195 PBD::EventLoop* event_loop) {
197 ir->event_loop = event_loop;
199 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2)));
202 void connect (ScopedConnection& c,
203 PBD::EventLoop::InvalidationRecord* ir,
204 const typename SignalType::slot_function_type& slot,
205 PBD::EventLoop* event_loop) {
207 ir->event_loop = event_loop;
209 c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2));
212 typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
213 return _signal (arg1, arg2);
216 bool empty() const { return _signal.empty(); }
222 template<typename R, typename A1, typename A2, typename A3>
226 typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
228 void connect_same_thread (ScopedConnectionList& clist,
229 const typename SignalType::slot_function_type& slot) {
230 clist.add_connection (_signal.connect (slot));
233 void connect_same_thread (ScopedConnection& c,
234 const typename SignalType::slot_function_type& slot) {
235 c = _signal.connect (slot);
238 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
239 EventLoop::InvalidationRecord* ir,
240 A1 arg1, A2 arg2, A3 arg3) {
241 event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3));
244 void connect (ScopedConnectionList& clist,
245 PBD::EventLoop::InvalidationRecord* ir,
246 const typename SignalType::slot_function_type& slot,
247 PBD::EventLoop* event_loop) {
249 ir->event_loop = event_loop;
251 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
254 void connect (ScopedConnection& c,
255 PBD::EventLoop::InvalidationRecord* ir,
256 const typename SignalType::slot_function_type& slot,
257 PBD::EventLoop* event_loop) {
259 ir->event_loop = event_loop;
261 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
264 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
265 return _signal (arg1, arg2, arg3);
268 bool empty() const { return _signal.empty(); }
274 template<typename R, typename A1, typename A2, typename A3, typename A4>
278 typedef boost::signals2::signal<R(A1,A2,A3,A4)> SignalType;
280 void connect_same_thread (ScopedConnectionList& clist,
281 const typename SignalType::slot_function_type& slot) {
282 clist.add_connection (_signal.connect (slot));
285 void connect_same_thread (ScopedConnection& c,
286 const typename SignalType::slot_function_type& slot) {
287 c = _signal.connect (slot);
290 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
291 EventLoop::InvalidationRecord* ir,
292 A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
293 event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3, arg4));
296 void connect (ScopedConnectionList& clist,
297 PBD::EventLoop::InvalidationRecord* ir,
298 const typename SignalType::slot_function_type& slot,
299 PBD::EventLoop* event_loop) {
301 ir->event_loop = event_loop;
303 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
306 void connect (ScopedConnection& c,
307 PBD::EventLoop::InvalidationRecord* ir,
308 const typename SignalType::slot_function_type& slot,
309 PBD::EventLoop* event_loop) {
311 ir->event_loop = event_loop;
313 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
316 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
317 return _signal (arg1, arg2, arg3, arg4);
320 bool empty() const { return _signal.empty(); }
326 template<typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
330 typedef boost::signals2::signal<R(A1,A2,A3,A4,A5)> SignalType;
332 void connect_same_thread (ScopedConnectionList& clist,
333 const typename SignalType::slot_function_type& slot) {
334 clist.add_connection (_signal.connect (slot));
337 void connect_same_thread (ScopedConnection& c,
338 const typename SignalType::slot_function_type& slot) {
339 c = _signal.connect (slot);
342 static void compositor (typename boost::function<void(A1,A2,A3,A4,A5)> f, PBD::EventLoop* event_loop,
343 EventLoop::InvalidationRecord* ir,
344 A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
345 event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3, arg4, arg5));
348 void connect (ScopedConnectionList& clist,
349 PBD::EventLoop::InvalidationRecord* ir,
350 const typename SignalType::slot_function_type& slot,
351 PBD::EventLoop* event_loop) {
353 ir->event_loop = event_loop;
355 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
358 void connect (ScopedConnection& c,
359 PBD::EventLoop::InvalidationRecord* ir,
360 const typename SignalType::slot_function_type& slot,
361 PBD::EventLoop* event_loop) {
363 ir->event_loop = event_loop;
365 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
368 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
369 return _signal (arg1, arg2, arg3, arg4, arg5);
372 bool empty() const { return _signal.empty(); }
380 #endif /* __pbd_signals_h__ */