47e8d143bc55f69e2781767a8079aad93f89d633
[ardour.git] / libs / pbd / pbd / signals.h
1 /*
2     Copyright (C) 2009 Paul Davis 
3
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.
8
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.
13
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.
17
18 */
19
20 #ifndef __pbd_signals_h__
21 #define __pbd_signals_h__
22
23 #include <list>
24 #include <glibmm/thread.h>
25 #include <boost/signals2.hpp>
26 #include <boost/noncopyable.hpp>
27
28 namespace PBD {
29
30 typedef boost::signals2::connection UnscopedConnection;
31 typedef boost::signals2::connection Connection;
32 typedef boost::signals2::scoped_connection ScopedConnection;
33
34 class ScopedConnectionList  : public boost::noncopyable
35 {
36   public:
37         ScopedConnectionList();
38         ~ScopedConnectionList ();
39         
40         void add_connection (const UnscopedConnection& c);
41         void drop_connections ();
42
43         template<typename S> void scoped_connect (S& sig, const typename S::slot_function_type& sf) {
44                 add_connection (sig.connect (sf));
45         }
46
47   private:
48         /* this class is not copyable */
49         ScopedConnectionList(const ScopedConnectionList&);
50
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:
58
59            (1) (unlikely) we make a connection involving a callback on the
60                same object from 2 threads. (wouldn't that just be appalling 
61                programming style?)
62              
63            (2) where we are dropping connections in one thread and adding
64                one from another.
65          */
66
67         static Glib::StaticMutex _lock;
68
69         typedef std::list<ScopedConnection*> ConnectionList;
70         ConnectionList _list;
71 };
72
73 template<typename R>
74 class Signal0 {
75 public:
76     Signal0 () {}
77     typedef boost::signals2::signal<R()> SignalType;
78
79     void connect (ScopedConnectionList& clist, 
80                   const typename SignalType::slot_function_type& slot) {
81             clist.add_connection (_signal.connect (slot));
82     }
83     
84     void connect (Connection& c, 
85                   const typename SignalType::slot_function_type& slot) {
86             c = _signal.connect (slot);
87     }
88     
89     typename SignalType::result_type operator()() {
90             return _signal ();
91     }
92     
93 private:
94     SignalType _signal;
95 };
96
97 template<typename R, typename A>
98 class Signal1 {
99 public:
100     Signal1 () {}
101     typedef boost::signals2::signal<R(A)> SignalType;
102
103     void connect (ScopedConnectionList& clist, 
104                   const typename SignalType::slot_function_type& slot) {
105             clist.add_connection (_signal.connect (slot));
106     }
107
108     void connect (Connection& c, 
109                   const typename SignalType::slot_function_type& slot) {
110             c = _signal.connect (slot);
111     }
112     
113     typename SignalType::result_type operator()(A arg1) {
114             return _signal (arg1);
115     }
116     
117 private:
118     SignalType _signal;
119 };
120
121 template<typename R, typename A1, typename A2>
122 class Signal2 {
123 public:
124     Signal2 () {}
125     typedef boost::signals2::signal<R(A1, A2)> SignalType;
126
127     void connect (ScopedConnectionList& clist, 
128                   const typename SignalType::slot_function_type& slot) {
129             clist.add_connection (_signal.connect (slot));
130     }
131     
132     void connect (Connection& c, 
133                   const typename SignalType::slot_function_type& slot) {
134             c = _signal.connect (slot);
135     }
136     
137     typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
138             return _signal (arg1, arg2);
139     }
140     
141 private:
142     SignalType _signal;
143 };
144
145 template<typename R, typename A1, typename A2, typename A3>
146 class Signal3 {
147 public:
148     Signal3 () {}
149     typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
150
151     void connect (ScopedConnectionList& clist, 
152                   const typename SignalType::slot_function_type& slot) {
153             clist.add_connection (_signal.connect (slot));
154     }
155     
156     void connect (Connection& c, 
157                   const typename SignalType::slot_function_type& slot) {
158             c = _signal.connect (slot);
159     }
160     
161     typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
162             return _signal (arg1, arg2, arg3);
163     }
164     
165 private:
166     SignalType _signal;
167 };
168
169 } /* namespace */
170
171 #endif /* __pbd_signals_h__ */