summaryrefslogtreecommitdiff
path: root/libs/pbd
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2012-05-14 17:18:48 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2012-05-14 17:18:48 +0000
commit1e0fd01815473b9d20d3144d437e2f7a8a9e680e (patch)
tree9895ef3fa90c68e34b6f68f18aacc104bd69d9d3 /libs/pbd
parent37969d837e16c8fbac0821074495b5ebc2297d94 (diff)
drop boost::signals2 and replace with carl's solution which continues to rely on boost::function and boost::bind but alters two important semantics of signals2: (1) when a Connection object is disconnected, the slot ("functor") associated with the connection is destroyed immediately, unlike signals2 where this is deferred to a subsequent connect/emit call on the signal (2) if one functor called by the signal disconnects another Connection, the functor represented by the Connection will NOT be called during the current signal emission (signals2 copies the slot list at the start of emission and calls everything in the slot list). this change fixes some very nasty crashes apparently caused by boost::signals2 assuming that the memory referenced by a functor remains valid after a disconnect (google will show other developers who had issues with this).
git-svn-id: svn://localhost/ardour2/branches/3.0@12265 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/pbd')
-rw-r--r--libs/pbd/base_ui.cc3
-rw-r--r--libs/pbd/pbd/signal.h903
-rw-r--r--libs/pbd/pbd/signal.h.py214
-rw-r--r--libs/pbd/pbd/signals.h143
-rw-r--r--libs/pbd/signals.cc2
-rw-r--r--libs/pbd/test/signals_test.cc48
-rw-r--r--libs/pbd/test/signals_test.h4
-rw-r--r--libs/pbd/test/xpath.cc14
8 files changed, 1262 insertions, 69 deletions
diff --git a/libs/pbd/base_ui.cc b/libs/pbd/base_ui.cc
index c246a50656..14a3ef644d 100644
--- a/libs/pbd/base_ui.cc
+++ b/libs/pbd/base_ui.cc
@@ -74,7 +74,6 @@ void
BaseUI::main_thread ()
{
DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: event loop running in thread %2\n", name(), pthread_self()));
- std::cerr << string_compose ("%1: event loop running in thread %2\n", name(), pthread_self());
set_event_loop_for_thread (this);
thread_init ();
_main_loop->get_context()->signal_idle().connect (sigc::mem_fun (*this, &BaseUI::signal_running));
@@ -104,9 +103,7 @@ BaseUI::run ()
Glib::Mutex::Lock lm (_run_lock);
run_loop_thread = Thread::create (mem_fun (*this, &BaseUI::main_thread), true);
- std::cerr << "wait for " << name() << " thread to start\n";
_running.wait (_run_lock);
- std::cerr << "\tthread now running\n";
}
void
diff --git a/libs/pbd/pbd/signal.h b/libs/pbd/pbd/signal.h
new file mode 100644
index 0000000000..5eb8520a6f
--- /dev/null
+++ b/libs/pbd/pbd/signal.h
@@ -0,0 +1,903 @@
+
+/** THIS FILE IS AUTOGENERATED: DO NOT EDIT.
+ *
+ * This file is generated by signals.h.py.
+ */
+
+#include <list>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/optional.hpp>
+#include "pbd/stacktrace.h"
+
+namespace PBD {
+
+class Connection;
+
+class SignalBase : public boost::enable_shared_from_this<SignalBase>
+{
+public:
+ virtual ~SignalBase () {}
+ virtual void disconnect (boost::shared_ptr<Connection>) = 0;
+
+protected:
+ boost::mutex _mutex;
+};
+
+class Connection : public boost::enable_shared_from_this<Connection>
+{
+public:
+ Connection (boost::shared_ptr<SignalBase> b) : _signal (b) {}
+
+ void disconnect ()
+ {
+ if (_signal) {
+ _signal->disconnect (shared_from_this ());
+ }
+ }
+
+private:
+ boost::shared_ptr<SignalBase> _signal;
+};
+
+template<typename R>
+class OptionalLastValue
+{
+public:
+ typedef boost::optional<R> result_type;
+
+ template <typename Iter>
+ result_type operator() (Iter first, Iter last) const {
+ result_type r;
+ while (first != last) {
+ r = *first;
+ ++first;
+ }
+
+ return r;
+ }
+};
+
+template <typename R, typename C = OptionalLastValue<R> >
+class SimpleSignal0 : public SignalBase
+{
+public:
+
+ typedef boost::function<R()> slot_function_type;
+ typedef boost::optional<R> result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ typename C::result_type emit ()
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ std::list<R> r;
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ r.push_back ((i->second)());
+ }
+ }
+ C c;
+ return c (r.begin(), r.end());
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal0<R, C> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal0<R, C> > (new SimpleSignal0<R, C>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal0 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <>
+class SimpleSignal0<void> : public SignalBase
+{
+public:
+
+ typedef boost::function<void()> slot_function_type;
+ typedef void result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ void emit ()
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+#else
+ for (Slots::iterator i = s.begin(); i != s.end(); ++i) {
+#endif
+
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ (i->second)();
+ }
+ }
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal0<void> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal0<void> > (new SimpleSignal0<void>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal0 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename R, typename A1, typename C = OptionalLastValue<R> >
+class SimpleSignal1 : public SignalBase
+{
+public:
+
+ typedef boost::function<R(A1)> slot_function_type;
+ typedef boost::optional<R> result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ typename C::result_type emit (A1 a1)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ std::list<R> r;
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ r.push_back ((i->second)(a1));
+ }
+ }
+ C c;
+ return c (r.begin(), r.end());
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal1<R, A1, C> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal1<R, A1, C> > (new SimpleSignal1<R, A1, C>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal1 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename A1>
+class SimpleSignal1<void, A1> : public SignalBase
+{
+public:
+
+ typedef boost::function<void(A1)> slot_function_type;
+ typedef void result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ void emit (A1 a1)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ (i->second)(a1);
+ }
+ }
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal1<void, A1> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal1<void, A1> > (new SimpleSignal1<void, A1>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal1 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename R, typename A1, typename A2, typename C = OptionalLastValue<R> >
+class SimpleSignal2 : public SignalBase
+{
+public:
+
+ typedef boost::function<R(A1, A2)> slot_function_type;
+ typedef boost::optional<R> result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ typename C::result_type emit (A1 a1, A2 a2)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ std::list<R> r;
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ r.push_back ((i->second)(a1, a2));
+ }
+ }
+ C c;
+ return c (r.begin(), r.end());
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal2<R, A1, A2, C> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal2<R, A1, A2, C> > (new SimpleSignal2<R, A1, A2, C>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal2 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename A1, typename A2>
+class SimpleSignal2<void, A1, A2> : public SignalBase
+{
+public:
+
+ typedef boost::function<void(A1, A2)> slot_function_type;
+ typedef void result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ void emit (A1 a1, A2 a2)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ (i->second)(a1, a2);
+ }
+ }
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal2<void, A1, A2> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal2<void, A1, A2> > (new SimpleSignal2<void, A1, A2>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal2 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename C = OptionalLastValue<R> >
+class SimpleSignal3 : public SignalBase
+{
+public:
+
+ typedef boost::function<R(A1, A2, A3)> slot_function_type;
+ typedef boost::optional<R> result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ typename C::result_type emit (A1 a1, A2 a2, A3 a3)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ std::list<R> r;
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ r.push_back ((i->second)(a1, a2, a3));
+ }
+ }
+ C c;
+ return c (r.begin(), r.end());
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal3<R, A1, A2, A3, C> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal3<R, A1, A2, A3, C> > (new SimpleSignal3<R, A1, A2, A3, C>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal3 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename A1, typename A2, typename A3>
+class SimpleSignal3<void, A1, A2, A3> : public SignalBase
+{
+public:
+
+ typedef boost::function<void(A1, A2, A3)> slot_function_type;
+ typedef void result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ void emit (A1 a1, A2 a2, A3 a3)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ (i->second)(a1, a2, a3);
+ }
+ }
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal3<void, A1, A2, A3> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal3<void, A1, A2, A3> > (new SimpleSignal3<void, A1, A2, A3>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal3 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4, typename C = OptionalLastValue<R> >
+class SimpleSignal4 : public SignalBase
+{
+public:
+
+ typedef boost::function<R(A1, A2, A3, A4)> slot_function_type;
+ typedef boost::optional<R> result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ typename C::result_type emit (A1 a1, A2 a2, A3 a3, A4 a4)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ std::list<R> r;
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ r.push_back ((i->second)(a1, a2, a3, a4));
+ }
+ }
+ C c;
+ return c (r.begin(), r.end());
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal4<R, A1, A2, A3, A4, C> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal4<R, A1, A2, A3, A4, C> > (new SimpleSignal4<R, A1, A2, A3, A4, C>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal4 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename A1, typename A2, typename A3, typename A4>
+class SimpleSignal4<void, A1, A2, A3, A4> : public SignalBase
+{
+public:
+
+ typedef boost::function<void(A1, A2, A3, A4)> slot_function_type;
+ typedef void result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ void emit (A1 a1, A2 a2, A3 a3, A4 a4)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ (i->second)(a1, a2, a3, a4);
+ }
+ }
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal4<void, A1, A2, A3, A4> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal4<void, A1, A2, A3, A4> > (new SimpleSignal4<void, A1, A2, A3, A4>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal4 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename C = OptionalLastValue<R> >
+class SimpleSignal5 : public SignalBase
+{
+public:
+
+ typedef boost::function<R(A1, A2, A3, A4, A5)> slot_function_type;
+ typedef boost::optional<R> result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ typename C::result_type emit (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ std::list<R> r;
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ r.push_back ((i->second)(a1, a2, a3, a4, a5));
+ }
+ }
+ C c;
+ return c (r.begin(), r.end());
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal5<R, A1, A2, A3, A4, A5, C> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal5<R, A1, A2, A3, A4, A5, C> > (new SimpleSignal5<R, A1, A2, A3, A4, A5, C>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal5 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+template <typename A1, typename A2, typename A3, typename A4, typename A5>
+class SimpleSignal5<void, A1, A2, A3, A4, A5> : public SignalBase
+{
+public:
+
+ typedef boost::function<void(A1, A2, A3, A4, A5)> slot_function_type;
+ typedef void result_type;
+private:
+
+
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+
+public:
+
+
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+
+ void emit (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
+ {
+ Slots s;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ s = _slots;
+ }
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {
+ (i->second)(a1, a2, a3, a4, a5);
+ }
+ }
+ }
+
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+
+ static boost::shared_ptr<SimpleSignal5<void, A1, A2, A3, A4, A5> > create ()
+ {
+ return boost::shared_ptr<SimpleSignal5<void, A1, A2, A3, A4, A5> > (new SimpleSignal5<void, A1, A2, A3, A4, A5>);
+ }
+
+private:
+
+ friend class Connection;
+
+ SimpleSignal5 () {}
+
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+
+}
diff --git a/libs/pbd/pbd/signal.h.py b/libs/pbd/pbd/signal.h.py
new file mode 100644
index 0000000000..70a1a2d88c
--- /dev/null
+++ b/libs/pbd/pbd/signal.h.py
@@ -0,0 +1,214 @@
+#!/usr/bin/python
+
+import sys
+
+if len(sys.argv) < 2:
+ print 'Syntax: %s <path>' % sys.argv[0]
+ sys.exit(1)
+
+f = open(sys.argv[1], 'w')
+
+print >>f,"""
+/** THIS FILE IS AUTOGENERATED: DO NOT EDIT.
+ *
+ * This file is generated by signals.h.py.
+ */
+
+#include <list>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/optional.hpp>
+#include "pbd/stacktrace.h"
+
+namespace PBD {
+
+class Connection;
+
+class SignalBase : public boost::enable_shared_from_this<SignalBase>
+{
+public:
+ virtual ~SignalBase () {}
+ virtual void disconnect (boost::shared_ptr<Connection>) = 0;
+
+protected:
+ boost::mutex _mutex;
+};
+
+class Connection : public boost::enable_shared_from_this<Connection>
+{
+public:
+ Connection (boost::shared_ptr<SignalBase> b) : _signal (b) {}
+
+ void disconnect ()
+ {
+ if (_signal) {
+ _signal->disconnect (shared_from_this ());
+ }
+ }
+
+private:
+ boost::shared_ptr<SignalBase> _signal;
+};
+
+template<typename R>
+class OptionalLastValue
+{
+public:
+ typedef boost::optional<R> result_type;
+
+ template <typename Iter>
+ result_type operator() (Iter first, Iter last) const {
+ result_type r;
+ while (first != last) {
+ r = *first;
+ ++first;
+ }
+
+ return r;
+ }
+};
+"""
+
+def comma_separated(n, prefix = ""):
+ r = ""
+ for i in range(0, len(n)):
+ if i > 0:
+ r += ", "
+ r += "%s%s" % (prefix, n[i])
+ return r
+
+def simple_signal(f, n, v):
+
+ An = []
+ for i in range(0, n):
+ An.append("A%d" % (i + 1))
+
+ if v:
+ print >>f,"template <%s>" % comma_separated(An, "typename ")
+ print >>f,"class SimpleSignal%d<%s> : public SignalBase" % (n, comma_separated(["void"] + An))
+ else:
+ print >>f,"template <%s>" % comma_separated(["R"] + An + ["C = OptionalLastValue<R> "], "typename ")
+ print >>f,"class SimpleSignal%d : public SignalBase" % n
+
+ print >>f,"{"
+ print >>f,"public:"
+ print >>f,""
+ if v:
+ print >>f,"\ttypedef boost::function<void(%s)> slot_function_type;" % comma_separated(An)
+ print >>f,"\ttypedef void result_type;"
+ else:
+ print >>f,"\ttypedef boost::function<R(%s)> slot_function_type;" % comma_separated(An)
+ print >>f,"\ttypedef boost::optional<R> result_type;"
+
+ print >>f,"private:"
+ print >>f,""
+
+ print >>f,"""
+ typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
+ Slots _slots;
+"""
+
+ print >>f,"public:"
+ print >>f,""
+ print >>f,"""
+ boost::shared_ptr<Connection> connect (slot_function_type f)
+ {
+ boost::shared_ptr<Connection> c (new Connection (shared_from_this ()));
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots[c] = f;
+ return c;
+ }
+"""
+
+ Anan = []
+ for a in An:
+ Anan.append('%s %s' % (a, a.lower()))
+
+ an = []
+ for a in An:
+ an.append(a.lower())
+
+ if v:
+ print >>f,"\tvoid emit (%s)" % comma_separated(Anan)
+ else:
+ print >>f,"\ttypename C::result_type emit (%s)" % comma_separated(Anan)
+ print >>f,"\t{"
+ print >>f,"\t\tSlots s;"
+ print >>f,"\t\t{"
+ print >>f,"\t\t\tboost::mutex::scoped_lock lm (_mutex);"
+ print >>f,"\t\t\ts = _slots;"
+ print >>f,"\t\t}"
+ if not v:
+ print >>f,"\t\tstd::list<R> r;"
+ if n == 0 and v:
+ print >>f,"""
+#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
+ for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {
+#else
+ for (Slots::iterator i = s.begin(); i != s.end(); ++i) {
+#endif
+"""
+ else:
+ print >>f,"\t\tfor (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {"
+
+ print >>f,"""
+ bool still_there = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ still_there = _slots.find (i->first) != _slots.end ();
+ }
+
+ if (still_there) {"""
+ if v:
+ print >>f,"\t\t\t\t(i->second)(%s);" % comma_separated(an)
+ else:
+ print >>f,"\t\t\t\tr.push_back ((i->second)(%s));" % comma_separated(an)
+ print >>f,"\t\t\t}"
+ print >>f,"\t\t}"
+ if not v:
+ print >>f,"\t\tC c;"
+ print >>f,"\t\treturn c (r.begin(), r.end());"
+ print >>f,"\t}"
+
+ print >>f,"""
+ bool empty () {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _slots.empty ();
+ }
+"""
+
+
+ if v:
+ tp = comma_separated(["void"] + An)
+ else:
+ tp = comma_separated(["R"] + An + ["C"])
+
+ print >>f,"\tstatic boost::shared_ptr<SimpleSignal%d<%s> > create ()" % (n, tp)
+ print >>f,"\t{"
+ print >>f,"\t\treturn boost::shared_ptr<SimpleSignal%d<%s> > (new SimpleSignal%d<%s>);" % (n, tp, n, tp)
+ print >>f,"\t}"
+
+ print >>f,""
+ print >>f,"private:"
+ print >>f,""
+ print >>f,"\tfriend class Connection;"
+ print >>f,""
+ print >>f,"\tSimpleSignal%d () {}" % n
+
+ print >>f,"""
+ void disconnect (boost::shared_ptr<Connection> c)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _slots.erase (c);
+ }
+};
+"""
+
+
+for i in range(0, 6):
+ simple_signal(f, i, False)
+ simple_signal(f, i, True)
+
+print >>f,"}"
diff --git a/libs/pbd/pbd/signals.h b/libs/pbd/pbd/signals.h
index cfada19879..7cdbcef414 100644
--- a/libs/pbd/pbd/signals.h
+++ b/libs/pbd/pbd/signals.h
@@ -23,23 +23,47 @@
#include <list>
#include <glibmm/thread.h>
-#include <boost/signals2.hpp>
#include <boost/noncopyable.hpp>
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include "pbd/event_loop.h"
+#include "pbd/signal.h"
namespace PBD {
-typedef boost::signals2::connection UnscopedConnection;
-typedef boost::signals2::scoped_connection ScopedConnection;
+typedef boost::shared_ptr<Connection> UnscopedConnection;
+class ScopedConnection
+{
+public:
+ ScopedConnection () {}
+ ScopedConnection (UnscopedConnection c) : _c (c) {}
+ ~ScopedConnection () {
+ disconnect ();
+ }
+
+ void disconnect ()
+ {
+ if (_c) {
+ _c->disconnect ();
+ }
+ }
+
+ ScopedConnection& operator= (UnscopedConnection const & o)
+ {
+ _c = o;
+ return *this;
+ }
+private:
+ UnscopedConnection _c;
+};
+
class ScopedConnectionList : public boost::noncopyable
{
public:
ScopedConnectionList();
- ~ScopedConnectionList ();
+ virtual ~ScopedConnectionList ();
void add_connection (const UnscopedConnection& c);
void drop_connections ();
@@ -73,8 +97,9 @@ class ScopedConnectionList : public boost::noncopyable
template<typename R>
class Signal0 {
public:
- Signal0 () {}
- typedef boost::signals2::signal<R()> SignalType;
+ typedef SimpleSignal0<R> SignalType;
+
+ Signal0 () : _signal (SignalType::create ()) {}
/** Arrange for @a slot to be executed whenever this signal is emitted.
Store the connection that represents this arrangement in @a c.
@@ -85,7 +110,7 @@ public:
void connect_same_thread (ScopedConnection& c,
const typename SignalType::slot_function_type& slot) {
- c = _signal.connect (slot);
+ c = _signal->connect (slot);
}
/** Arrange for @a slot to be executed whenever this signal is emitted.
@@ -97,7 +122,7 @@ public:
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {
- clist.add_connection (_signal.connect (slot));
+ clist.add_connection (_signal->connect (slot));
}
/** Arrange for @a slot to be executed in the context of @a event_loop
@@ -132,7 +157,7 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- clist.add_connection (_signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot)));
+ clist.add_connection (_signal->connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot)));
}
/** See notes for the ScopedConnectionList variant of this function. This
@@ -147,7 +172,7 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot));
+ c = _signal->connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot));
}
/** Emit this signal. This will cause all slots connected to it be executed
@@ -156,33 +181,33 @@ public:
*/
typename SignalType::result_type operator()() {
- return _signal ();
+ return _signal->emit ();
}
/** Return true if there is nothing connected to this signal, false
* otherwise.
*/
- bool empty() const { return _signal.empty(); }
+ bool empty() const { return _signal->empty(); }
private:
- SignalType _signal;
+ boost::shared_ptr<SignalType> _signal;
};
-template<typename R, typename A, typename C = boost::signals2::optional_last_value<R> >
+template<typename R, typename A, typename C = OptionalLastValue<R> >
class Signal1 {
public:
- Signal1 () {}
- typedef boost::signals2::signal<R(A), C> SignalType;
+ typedef SimpleSignal1<R, A, C> SignalType;
+ Signal1 () : _signal (SignalType::create()) {}
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {
- clist.add_connection (_signal.connect (slot));
+ clist.add_connection (_signal->connect (slot));
}
void connect_same_thread (ScopedConnection& c,
const typename SignalType::slot_function_type& slot) {
- c = _signal.connect (slot);
+ c = _signal->connect (slot);
}
static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir, A arg) {
@@ -196,7 +221,7 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1)));
+ clist.add_connection (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1)));
}
void connect (ScopedConnection& c,
@@ -206,34 +231,34 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1));
+ c = _signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1));
}
typename SignalType::result_type operator()(A arg1) {
- return _signal (arg1);
+ return _signal->emit (arg1);
}
- bool empty() const { return _signal.empty(); }
+ bool empty() const { return _signal->empty(); }
private:
- SignalType _signal;
+ boost::shared_ptr<SignalType> _signal;
};
template<typename R, typename A1, typename A2>
class Signal2 {
public:
- Signal2 () {}
- typedef boost::signals2::signal<R(A1, A2)> SignalType;
+ typedef SimpleSignal2<R, A1, A2> SignalType;
+ Signal2 () : _signal (SignalType::create()) {}
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {
- clist.add_connection (_signal.connect (slot));
+ clist.add_connection (_signal->connect (slot));
}
void connect_same_thread (ScopedConnection& c,
const typename SignalType::slot_function_type& slot) {
- c = _signal.connect (slot);
+ c = _signal->connect (slot);
}
static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop,
@@ -249,7 +274,7 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2)));
+ clist.add_connection (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2)));
}
void connect (ScopedConnection& c,
@@ -259,33 +284,33 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2));
+ c = _signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2));
}
typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
- return _signal (arg1, arg2);
+ return _signal->emit (arg1, arg2);
}
- bool empty() const { return _signal.empty(); }
+ bool empty() const { return _signal->empty(); }
private:
- SignalType _signal;
+ boost::shared_ptr<SignalType> _signal;
};
template<typename R, typename A1, typename A2, typename A3>
class Signal3 {
public:
- Signal3 () {}
- typedef boost::signals2::signal<R(A1,A2,A3)> SignalType;
+ typedef SimpleSignal3<R, A1, A2, A3> SignalType;
+ Signal3 () : _signal (SignalType::create()) {}
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {
- clist.add_connection (_signal.connect (slot));
+ clist.add_connection (_signal->connect (slot));
}
void connect_same_thread (ScopedConnection& c,
const typename SignalType::slot_function_type& slot) {
- c = _signal.connect (slot);
+ c = _signal->connect (slot);
}
static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
@@ -301,7 +326,7 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
+ clist.add_connection (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
}
void connect (ScopedConnection& c,
@@ -311,33 +336,33 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
+ c = _signal->connect (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
}
typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
- return _signal (arg1, arg2, arg3);
+ return _signal->emit (arg1, arg2, arg3);
}
- bool empty() const { return _signal.empty(); }
+ bool empty() const { return _signal->empty(); }
private:
- SignalType _signal;
+ boost::shared_ptr<SignalType> _signal;
};
template<typename R, typename A1, typename A2, typename A3, typename A4>
class Signal4 {
public:
- Signal4 () {}
- typedef boost::signals2::signal<R(A1,A2,A3,A4)> SignalType;
+ typedef SimpleSignal4<R, A1, A2, A3, A4> SignalType;
+ Signal4 () : _signal (SignalType::create()) {}
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {
- clist.add_connection (_signal.connect (slot));
+ clist.add_connection (_signal->connect (slot));
}
void connect_same_thread (ScopedConnection& c,
const typename SignalType::slot_function_type& slot) {
- c = _signal.connect (slot);
+ c = _signal->connect (slot);
}
static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
@@ -353,7 +378,7 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
+ clist.add_connection (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
}
void connect (ScopedConnection& c,
@@ -363,33 +388,33 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
+ c = _signal->connect (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
}
typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
- return _signal (arg1, arg2, arg3, arg4);
+ return _signal->emit (arg1, arg2, arg3, arg4);
}
- bool empty() const { return _signal.empty(); }
+ bool empty() const { return _signal->empty(); }
private:
- SignalType _signal;
+ boost::shared_ptr<SignalType> _signal;
};
template<typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
class Signal5 {
public:
- Signal5 () {}
- typedef boost::signals2::signal<R(A1,A2,A3,A4,A5)> SignalType;
+ typedef SimpleSignal5<R, A1, A2, A3, A4, A5> SignalType;
+ Signal5 () : _signal (SignalType::create()) {}
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {
- clist.add_connection (_signal.connect (slot));
+ clist.add_connection (_signal->connect (slot));
}
void connect_same_thread (ScopedConnection& c,
const typename SignalType::slot_function_type& slot) {
- c = _signal.connect (slot);
+ c = _signal->connect (slot);
}
static void compositor (typename boost::function<void(A1,A2,A3,A4,A5)> f, PBD::EventLoop* event_loop,
@@ -405,7 +430,7 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
+ clist.add_connection (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
}
void connect (ScopedConnection& c,
@@ -415,17 +440,17 @@ public:
if (ir) {
ir->event_loop = event_loop;
}
- c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
+ c = _signal->connect (_signal->connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4, _5)));
}
typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
- return _signal (arg1, arg2, arg3, arg4, arg5);
+ return _signal->emit (arg1, arg2, arg3, arg4, arg5);
}
- bool empty() const { return _signal.empty(); }
+ bool empty() const { return _signal->empty(); }
private:
- SignalType _signal;
+ boost::shared_ptr<SignalType> _signal;
};
} /* namespace */
diff --git a/libs/pbd/signals.cc b/libs/pbd/signals.cc
index 62cabff091..b37c6e211a 100644
--- a/libs/pbd/signals.cc
+++ b/libs/pbd/signals.cc
@@ -18,6 +18,7 @@
*/
#include "pbd/signals.h"
+#include "pbd/demangle.h"
using namespace PBD;
@@ -29,6 +30,7 @@ ScopedConnectionList::ScopedConnectionList()
ScopedConnectionList::~ScopedConnectionList()
{
+ std::cout << "~ScopedConnectionList " << this << " " << PBD::demangled_name (*this) << "\n";
drop_connections ();
}
diff --git a/libs/pbd/test/signals_test.cc b/libs/pbd/test/signals_test.cc
index f635ea63da..9ca1bf536b 100644
--- a/libs/pbd/test/signals_test.cc
+++ b/libs/pbd/test/signals_test.cc
@@ -1,6 +1,8 @@
#include "signals_test.h"
#include "pbd/signals.h"
+using namespace std;
+
CPPUNIT_TEST_SUITE_REGISTRATION (SignalsTest);
class Emitter {
@@ -12,10 +14,30 @@ public:
PBD::Signal0<void> Fred;
};
+static int N = 0;
+
void
receiver ()
{
+ ++N;
+}
+void
+SignalsTest::testEmission ()
+{
+ Emitter* e = new Emitter;
+ PBD::ScopedConnection c;
+ e->Fred.connect_same_thread (c, boost::bind (&receiver));
+
+ N = 0;
+ e->emit ();
+ e->emit ();
+ CPPUNIT_ASSERT_EQUAL (2, N);
+
+ e->Fred.connect_same_thread (c, boost::bind (&receiver));
+ N = 0;
+ e->emit ();
+ CPPUNIT_ASSERT_EQUAL (2, N);
}
void
@@ -31,3 +53,29 @@ SignalsTest::testDestruction ()
CPPUNIT_ASSERT (true);
}
+class Receiver : public PBD::ScopedConnectionList
+{
+public:
+ Receiver (Emitter* e) {
+ e->Fred.connect_same_thread (*this, boost::bind (&Receiver::receiver, this));
+ }
+
+ void receiver () {
+ cout << "Receiver::receiver\n";
+ ++N;
+ }
+};
+
+void
+SignalsTest::testScopedConnectionList ()
+{
+ Emitter* e = new Emitter;
+ Receiver* r = new Receiver (e);
+
+ N = 0;
+ e->emit ();
+ delete r;
+ e->emit ();
+
+ CPPUNIT_ASSERT_EQUAL (1, N);
+}
diff --git a/libs/pbd/test/signals_test.h b/libs/pbd/test/signals_test.h
index 9a66564705..8beb02ab1e 100644
--- a/libs/pbd/test/signals_test.h
+++ b/libs/pbd/test/signals_test.h
@@ -4,9 +4,13 @@
class SignalsTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE (SignalsTest);
+ CPPUNIT_TEST (testEmission);
CPPUNIT_TEST (testDestruction);
+ CPPUNIT_TEST (testScopedConnectionList);
CPPUNIT_TEST_SUITE_END ();
public:
+ void testEmission ();
void testDestruction ();
+ void testScopedConnectionList ();
};
diff --git a/libs/pbd/test/xpath.cc b/libs/pbd/test/xpath.cc
index 15062c6132..f0e976eabd 100644
--- a/libs/pbd/test/xpath.cc
+++ b/libs/pbd/test/xpath.cc
@@ -13,12 +13,12 @@ static string const prefix = "../libs/pbd/test/";
void
XPathTest::testMisc ()
{
- cout << "Test 1: RosegardenPatchFile.xml: Find all banks in the file" << endl;
+// cout << "Test 1: RosegardenPatchFile.xml: Find all banks in the file" << endl;
XMLTree doc(prefix + "RosegardenPatchFile.xml");
// "//bank" gives as last element an empty element libxml bug????
boost::shared_ptr<XMLSharedNodeList> result = doc.find("//bank[@name]");
- cout << "Found " << result->size() << " banks" << endl;
+// cout << "Found " << result->size() << " banks" << endl;
assert(result->size() == 8);
// int counter = 1;
for(XMLSharedNodeList::const_iterator i = result->begin(); i != result->end(); ++i) {
@@ -31,7 +31,7 @@ XPathTest::testMisc ()
}
}
- cout << endl << endl << "Test 2: RosegardenPatchFile.xml: Find all programs whose program name contains 'Latin'" << endl;
+// cout << endl << endl << "Test 2: RosegardenPatchFile.xml: Find all programs whose program name contains 'Latin'" << endl;
result = doc.find("/rosegarden-data/studio/device/bank/program[contains(@name, 'Latin')]");
assert(result->size() == 5);
@@ -53,7 +53,7 @@ XPathTest::testMisc ()
// "' with id: " << (*i)->property("id")->value() << endl;
}
- cout << endl << endl << "Test 4: TestSession.ardour: Find all elements with an 'id' and 'name' attribute" << endl;
+// cout << endl << endl << "Test 4: TestSession.ardour: Find all elements with an 'id' and 'name' attribute" << endl;
result = doc2.find("//*[@id and @name]");
@@ -65,7 +65,7 @@ XPathTest::testMisc ()
// "' and name: " << (*i)->property("name")->value() << endl;
}
- cout << endl << endl << "Test 5: ProtoolsPatchFile.midnam: Get Banks and Patches for 'Name Set 1'" << endl;
+// cout << endl << endl << "Test 5: ProtoolsPatchFile.midnam: Get Banks and Patches for 'Name Set 1'" << endl;
// We have to allocate a new document here, or we get segfaults
XMLTree doc3(prefix + "ProtoolsPatchFile.midnam");
@@ -81,7 +81,7 @@ XPathTest::testMisc ()
}
}
- cout << endl << endl << "Test 5: ProtoolsPatchFile.midnam: Find attribute nodes" << endl;
+// cout << endl << endl << "Test 5: ProtoolsPatchFile.midnam: Find attribute nodes" << endl;
result = doc3.find("//@Value");
for(XMLSharedNodeList::const_iterator i = result->begin(); i != result->end(); ++i) {
@@ -90,7 +90,7 @@ XPathTest::testMisc ()
// << " value: " << node->attribute_value() << endl;
}
- cout << endl << endl << "Test 6: ProtoolsPatchFile.midnam: Find available channels on 'Name Set 1'" << endl;
+// cout << endl << endl << "Test 6: ProtoolsPatchFile.midnam: Find available channels on 'Name Set 1'" << endl;
result = doc3.find(
"//ChannelNameSet[@Name = 'Name Set 1']//AvailableChannel[@Available = 'true']/@Channel");