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 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, slot)));
96 void connect (Connection& c,
97 const typename SignalType::slot_function_type& slot,
98 PBD::EventLoop* event_loop) {
99 c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, slot));
102 typename SignalType::result_type operator()() {
106 bool empty() const { return _signal.empty(); }
112 template<typename R, typename A>
116 typedef boost::signals2::signal<R(A)> SignalType;
118 void connect_same_thread (ScopedConnectionList& clist,
119 const typename SignalType::slot_function_type& slot) {
120 clist.add_connection (_signal.connect (slot));
123 void connect_same_thread (Connection& c,
124 const typename SignalType::slot_function_type& slot) {
125 c = _signal.connect (slot);
128 static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, A arg) {
129 event_loop->call_slot (boost::bind (f, arg));
132 void connect (ScopedConnectionList& clist,
133 const typename SignalType::slot_function_type& slot,
134 PBD::EventLoop* event_loop) {
135 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1)));
138 void connect (Connection& c,
139 const typename SignalType::slot_function_type& slot,
140 PBD::EventLoop* event_loop) {
141 c = _signal.connect (boost::bind (&compositor, slot, event_loop, _1));
145 typename SignalType::result_type operator()(A arg1) {
146 return _signal (arg1);
149 bool empty() const { return _signal.empty(); }
155 template<typename R, typename A1, typename A2>
159 typedef boost::signals2::signal<R(A1, A2)> SignalType;
161 void connect_same_thread (ScopedConnectionList& clist,
162 const typename SignalType::slot_function_type& slot) {
163 clist.add_connection (_signal.connect (slot));
166 void connect_same_thread (Connection& c,
167 const typename SignalType::slot_function_type& slot) {
168 c = _signal.connect (slot);
171 static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2) {
172 event_loop->call_slot (boost::bind (f, arg1, arg2));
175 void connect (ScopedConnectionList& clist,
176 const typename SignalType::slot_function_type& slot,
177 PBD::EventLoop* event_loop) {
178 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2)));
181 void connect (Connection& c,
182 const typename SignalType::slot_function_type& slot,
183 PBD::EventLoop* event_loop) {
184 c = _signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2));
187 typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
188 return _signal (arg1, arg2);
191 bool empty() const { return _signal.empty(); }
197 template<typename R, typename A1, typename A2, typename A3>
201 typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
203 void connect_same_thread (ScopedConnectionList& clist,
204 const typename SignalType::slot_function_type& slot) {
205 clist.add_connection (_signal.connect (slot));
208 void connect_same_thread (Connection& c,
209 const typename SignalType::slot_function_type& slot) {
210 c = _signal.connect (slot);
213 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2, A3 arg3) {
214 event_loop->call_slot (boost::bind (f, arg1, arg2, arg3));
217 void connect (ScopedConnectionList& clist,
218 const typename SignalType::slot_function_type& slot,
219 PBD::EventLoop* event_loop) {
220 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3)));
223 void connect (Connection& c,
224 const typename SignalType::slot_function_type& slot,
225 PBD::EventLoop* event_loop) {
226 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3)));
229 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
230 return _signal (arg1, arg2, arg3);
233 bool empty() const { return _signal.empty(); }
239 template<typename R, typename A1, typename A2, typename A3, typename A4>
243 typedef boost::signals2::signal<R(A1,A2,A3,A4)> SignalType;
245 void connect_same_thread (ScopedConnectionList& clist,
246 const typename SignalType::slot_function_type& slot) {
247 clist.add_connection (_signal.connect (slot));
250 void connect_same_thread (Connection& c,
251 const typename SignalType::slot_function_type& slot) {
252 c = _signal.connect (slot);
255 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
256 event_loop->call_slot (boost::bind (f, arg1, arg2, arg3, arg4));
259 void connect (ScopedConnectionList& clist,
260 const typename SignalType::slot_function_type& slot,
261 PBD::EventLoop* event_loop) {
262 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3, _4)));
265 void connect (Connection& c,
266 const typename SignalType::slot_function_type& slot,
267 PBD::EventLoop* event_loop) {
268 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3, _4)));
271 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
272 return _signal (arg1, arg2, arg3, arg4);
275 bool empty() const { return _signal.empty(); }
283 #endif /* __pbd_signals_h__ */