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()() {
110 template<typename R, typename A>
114 typedef boost::signals2::signal<R(A)> SignalType;
116 void connect_same_thread (ScopedConnectionList& clist,
117 const typename SignalType::slot_function_type& slot) {
118 clist.add_connection (_signal.connect (slot));
121 void connect_same_thread (Connection& c,
122 const typename SignalType::slot_function_type& slot) {
123 c = _signal.connect (slot);
126 static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, A arg) {
127 event_loop->call_slot (boost::bind (f, arg));
130 void connect (ScopedConnectionList& clist,
131 const typename SignalType::slot_function_type& slot,
132 PBD::EventLoop* event_loop) {
133 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1)));
136 void connect (Connection& c,
137 const typename SignalType::slot_function_type& slot,
138 PBD::EventLoop* event_loop) {
139 c = _signal.connect (boost::bind (&compositor, slot, event_loop, _1));
143 typename SignalType::result_type operator()(A arg1) {
144 return _signal (arg1);
151 template<typename R, typename A1, typename A2>
155 typedef boost::signals2::signal<R(A1, A2)> SignalType;
157 void connect_same_thread (ScopedConnectionList& clist,
158 const typename SignalType::slot_function_type& slot) {
159 clist.add_connection (_signal.connect (slot));
162 void connect_same_thread (Connection& c,
163 const typename SignalType::slot_function_type& slot) {
164 c = _signal.connect (slot);
167 static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2) {
168 event_loop->call_slot (boost::bind (f, arg1, arg2));
171 void connect (ScopedConnectionList& clist,
172 const typename SignalType::slot_function_type& slot,
173 PBD::EventLoop* event_loop) {
174 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2)));
177 void connect (Connection& c,
178 const typename SignalType::slot_function_type& slot,
179 PBD::EventLoop* event_loop) {
180 c = _signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2));
183 typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
184 return _signal (arg1, arg2);
191 template<typename R, typename A1, typename A2, typename A3>
195 typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
197 void connect_same_thread (ScopedConnectionList& clist,
198 const typename SignalType::slot_function_type& slot) {
199 clist.add_connection (_signal.connect (slot));
202 void connect_same_thread (Connection& c,
203 const typename SignalType::slot_function_type& slot) {
204 c = _signal.connect (slot);
207 static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2, A3 arg3) {
208 event_loop->call_slot (boost::bind (f, arg1, arg2, arg3));
211 void connect (ScopedConnectionList& clist,
212 const typename SignalType::slot_function_type& slot,
213 PBD::EventLoop* event_loop) {
214 clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3)));
217 void connect (Connection& c,
218 const typename SignalType::slot_function_type& slot,
219 PBD::EventLoop* event_loop) {
220 c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3)));
223 typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
224 return _signal (arg1, arg2, arg3);
233 #endif /* __pbd_signals_h__ */