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