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