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