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