e40b0bd2a47d868f4d74a1329bbcced0a8e35658
[ardour.git] / libs / pbd / pbd / signals.h
1 /*
2     Copyright (C) 2009-2012 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/noncopyable.hpp>
27 #include <boost/bind.hpp>
28 #include <boost/bind/protect.hpp>
29 #include <boost/function.hpp>
30 #include <boost/thread/mutex.hpp>
31 #include <boost/enable_shared_from_this.hpp>
32 #include <boost/optional.hpp>
33
34 #include "pbd/event_loop.h"
35
36 namespace PBD {
37
38 class Connection;
39
40 class SignalBase
41 {
42 public:
43         virtual ~SignalBase () {}
44         virtual void disconnect (boost::shared_ptr<Connection>) = 0;
45
46 protected:
47         boost::mutex _mutex;
48 };
49
50 class Connection : public boost::enable_shared_from_this<Connection>
51 {
52 public:
53         Connection (SignalBase* b) : _signal (b) {}
54
55         void disconnect ()
56         {
57                 boost::mutex::scoped_lock lm (_mutex);
58                 if (_signal) {
59                         _signal->disconnect (shared_from_this ());
60                 } 
61         }
62
63         void signal_going_away ()
64         {
65                 boost::mutex::scoped_lock lm (_mutex);
66                 _signal = 0;
67         }
68
69 private:
70         boost::mutex _mutex;
71         SignalBase* _signal;
72 };
73
74 template<typename R>
75 class OptionalLastValue
76 {
77 public:
78         typedef boost::optional<R> result_type;
79
80         template <typename Iter>
81         result_type operator() (Iter first, Iter last) const {
82                 result_type r;
83                 while (first != last) {
84                         r = *first;
85                         ++first;
86                 }
87
88                 return r;
89         }
90 };
91         
92 typedef boost::shared_ptr<Connection> UnscopedConnection;
93         
94 class ScopedConnection
95 {
96 public:
97         ScopedConnection () {}
98         ScopedConnection (UnscopedConnection c) : _c (c) {}
99         ~ScopedConnection () {
100                 disconnect ();
101         }
102
103         void disconnect ()
104         {
105                 if (_c) {
106                         _c->disconnect ();
107                 }
108         }
109
110         ScopedConnection& operator= (UnscopedConnection const & o)
111         {
112                 _c = o;
113                 return *this;
114         }
115
116 private:
117         UnscopedConnection _c;
118 };
119         
120 class ScopedConnectionList  : public boost::noncopyable
121 {
122   public:
123         ScopedConnectionList();
124         virtual ~ScopedConnectionList ();
125         
126         void add_connection (const UnscopedConnection& c);
127         void drop_connections ();
128
129   private:
130         /* this class is not copyable */
131         ScopedConnectionList(const ScopedConnectionList&);
132
133         /* this lock is shared by all instances of a ScopedConnectionList.
134            We do not want one mutex per list, and since we only need the lock
135            when adding or dropping connections, which are generally occuring
136            in object creation and UI operations, the contention on this 
137            lock is low and not of significant consequence. Even though
138            boost::signals2 is thread-safe, this additional list of
139            scoped connections needs to be protected in 2 cases:
140
141            (1) (unlikely) we make a connection involving a callback on the
142                same object from 2 threads. (wouldn't that just be appalling 
143                programming style?)
144              
145            (2) where we are dropping connections in one thread and adding
146                one from another.
147          */
148
149         static Glib::StaticMutex _lock;
150
151         typedef std::list<ScopedConnection*> ConnectionList;
152         ConnectionList _list;
153 };
154
155 #include "pbd/signals_generated.h"      
156         
157 } /* namespace */
158
159 #endif /* __pbd_signals_h__ */