tweak transport bar spacing
[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
26 #include <boost/signals2.hpp>
27 #include <boost/noncopyable.hpp>
28 #include <boost/bind.hpp>
29 #include <boost/bind/protect.hpp>
30
31 #include "pbd/event_loop.h"
32
33 namespace PBD {
34
35 typedef boost::signals2::connection UnscopedConnection;
36 typedef boost::signals2::scoped_connection ScopedConnection;
37
38 class ScopedConnectionList  : public boost::noncopyable
39 {
40   public:
41         ScopedConnectionList();
42         ~ScopedConnectionList ();
43         
44         void add_connection (const UnscopedConnection& c);
45         void drop_connections ();
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_same_thread (ScopedConnection& c, 
80                   const typename SignalType::slot_function_type& slot) {
81             c = _signal.connect (slot);
82     }
83
84     void connect_same_thread (ScopedConnectionList& clist, 
85                   const typename SignalType::slot_function_type& slot) {
86             clist.add_connection (_signal.connect (slot));
87     }
88
89     void connect (ScopedConnectionList& clist, 
90                   PBD::EventLoop::InvalidationRecord* ir, 
91                   const typename SignalType::slot_function_type& slot,
92                   PBD::EventLoop* event_loop) {
93             if (ir) {
94                     ir->event_loop = event_loop;
95             }
96             clist.add_connection (_signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot)));
97     }
98     
99     void connect (ScopedConnection& c, 
100                   PBD::EventLoop::InvalidationRecord* ir, 
101                   const typename SignalType::slot_function_type& slot,
102                   PBD::EventLoop* event_loop) {
103             if (ir) {
104                     ir->event_loop = event_loop;
105             }
106             c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot));
107     }
108     
109     typename SignalType::result_type operator()() {
110             return _signal ();
111     }
112
113     bool empty() const { return _signal.empty(); }
114     
115 private:
116     SignalType _signal;
117 };
118
119 template<typename R, typename A, typename C = boost::signals2::optional_last_value<R> >
120 class Signal1 {
121 public:
122     Signal1 () {}
123     typedef boost::signals2::signal<R(A), C> SignalType;
124
125     void connect_same_thread (ScopedConnectionList& clist, 
126                   const typename SignalType::slot_function_type& slot) {
127             clist.add_connection (_signal.connect (slot));
128     }
129
130     void connect_same_thread (ScopedConnection& c, 
131                      const typename SignalType::slot_function_type& slot) {
132             c = _signal.connect (slot);
133     }
134
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));
137     }
138
139     void connect (ScopedConnectionList& clist, 
140                   PBD::EventLoop::InvalidationRecord* ir, 
141                   const typename SignalType::slot_function_type& slot,
142                   PBD::EventLoop* event_loop) {
143             if (ir) {
144                     ir->event_loop = event_loop;
145             }
146             clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1)));
147     }
148
149     void connect (ScopedConnection& c, 
150                   PBD::EventLoop::InvalidationRecord* ir, 
151                   const typename SignalType::slot_function_type& slot,
152                   PBD::EventLoop* event_loop) {
153             if (ir) {
154                     ir->event_loop = event_loop;
155             }
156             c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1));
157
158     }
159     
160     typename SignalType::result_type operator()(A arg1) {
161             return _signal (arg1);
162     }
163     
164     bool empty() const { return _signal.empty(); }
165
166 private:
167     SignalType _signal;
168 };
169
170 template<typename R, typename A1, typename A2>
171 class Signal2 {
172 public:
173     Signal2 () {}
174     typedef boost::signals2::signal<R(A1, A2)> SignalType;
175
176     void connect_same_thread (ScopedConnectionList& clist, 
177                   const typename SignalType::slot_function_type& slot) {
178             clist.add_connection (_signal.connect (slot));
179     }
180
181     void connect_same_thread (ScopedConnection& c, 
182                      const typename SignalType::slot_function_type& slot) {
183             c = _signal.connect (slot);
184     }
185
186     static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop, 
187                             EventLoop::InvalidationRecord* ir,
188                             A1 arg1, A2 arg2) {
189             event_loop->call_slot (ir, boost::bind (f, arg1, arg2));
190     }
191
192     void connect (ScopedConnectionList& clist, 
193                   PBD::EventLoop::InvalidationRecord* ir, 
194                   const typename SignalType::slot_function_type& slot,
195                   PBD::EventLoop* event_loop) {
196             if (ir) {
197                     ir->event_loop = event_loop;
198             }
199             clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2)));
200     }
201
202     void connect (ScopedConnection& c, 
203                   PBD::EventLoop::InvalidationRecord* ir, 
204                   const typename SignalType::slot_function_type& slot,
205                   PBD::EventLoop* event_loop) {
206             if (ir) {
207                     ir->event_loop = event_loop;
208             }
209             c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2));
210     }
211
212     typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
213             return _signal (arg1, arg2);
214     }
215     
216     bool empty() const { return _signal.empty(); }
217
218 private:
219     SignalType _signal;
220 };
221
222 template<typename R, typename A1, typename A2, typename A3>
223 class Signal3 {
224 public:
225     Signal3 () {}
226     typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
227
228     void connect_same_thread (ScopedConnectionList& clist, 
229                   const typename SignalType::slot_function_type& slot) {
230             clist.add_connection (_signal.connect (slot));
231     }
232
233     void connect_same_thread (ScopedConnection& c, 
234                               const typename SignalType::slot_function_type& slot) {
235             c = _signal.connect (slot);
236     }
237
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));
242     }
243
244     void connect (ScopedConnectionList& clist, 
245                   PBD::EventLoop::InvalidationRecord* ir, 
246                   const typename SignalType::slot_function_type& slot,
247                   PBD::EventLoop* event_loop) {
248             if (ir) {
249                     ir->event_loop = event_loop;
250             }
251             clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
252     }
253     
254     void connect (ScopedConnection& c, 
255                   PBD::EventLoop::InvalidationRecord* ir, 
256                   const typename SignalType::slot_function_type& slot,
257                   PBD::EventLoop* event_loop) {
258             if (ir) {
259                     ir->event_loop = event_loop;
260             }
261             c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
262     }
263     
264     typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
265             return _signal (arg1, arg2, arg3);
266     }
267     
268     bool empty() const { return _signal.empty(); }
269
270 private:
271     SignalType _signal;
272 };
273
274 template<typename R, typename A1, typename A2, typename A3, typename A4>
275 class Signal4 {
276 public:
277     Signal4 () {}
278     typedef boost::signals2::signal<R(A1,A2,A3,A4)> SignalType;
279
280     void connect_same_thread (ScopedConnectionList& clist, 
281                   const typename SignalType::slot_function_type& slot) {
282             clist.add_connection (_signal.connect (slot));
283     }
284
285     void connect_same_thread (ScopedConnection& c, 
286                               const typename SignalType::slot_function_type& slot) {
287             c = _signal.connect (slot);
288     }
289
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));
294     }
295
296     void connect (ScopedConnectionList& clist, 
297                   PBD::EventLoop::InvalidationRecord* ir, 
298                   const typename SignalType::slot_function_type& slot,
299                   PBD::EventLoop* event_loop) {
300             if (ir) {
301                     ir->event_loop = event_loop;
302             }
303             clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
304     }
305     
306     void connect (ScopedConnection& c, 
307                   PBD::EventLoop::InvalidationRecord* ir, 
308                   const typename SignalType::slot_function_type& slot,
309                   PBD::EventLoop* event_loop) {
310             if (ir) {
311                     ir->event_loop = event_loop;
312             }
313             c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
314     }
315     
316     typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
317             return _signal (arg1, arg2, arg3, arg4);
318     }
319     
320     bool empty() const { return _signal.empty(); }
321
322 private:
323     SignalType _signal;
324 };
325
326 template<typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
327 class Signal5 {
328 public:
329     Signal5 () {}
330     typedef boost::signals2::signal<R(A1,A2,A3,A4,A5)> SignalType;
331
332     void connect_same_thread (ScopedConnectionList& clist, 
333                   const typename SignalType::slot_function_type& slot) {
334             clist.add_connection (_signal.connect (slot));
335     }
336
337     void connect_same_thread (ScopedConnection& c, 
338                               const typename SignalType::slot_function_type& slot) {
339             c = _signal.connect (slot);
340     }
341
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));
346     }
347
348     void connect (ScopedConnectionList& clist, 
349                   PBD::EventLoop::InvalidationRecord* ir, 
350                   const typename SignalType::slot_function_type& slot,
351                   PBD::EventLoop* event_loop) {
352             if (ir) {
353                     ir->event_loop = event_loop;
354             }
355             clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
356     }
357     
358     void connect (ScopedConnection& c, 
359                   PBD::EventLoop::InvalidationRecord* ir, 
360                   const typename SignalType::slot_function_type& slot,
361                   PBD::EventLoop* event_loop) {
362             if (ir) {
363                     ir->event_loop = event_loop;
364             }
365             c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
366     }
367     
368     typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
369             return _signal (arg1, arg2, arg3, arg4, arg5);
370     }
371     
372     bool empty() const { return _signal.empty(); }
373
374 private:
375     SignalType _signal;
376 };
377         
378 } /* namespace */
379
380 #endif /* __pbd_signals_h__ */