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