diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 2451611b1b..1ba27a7449 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -152,7 +152,7 @@ class IO : public SessionObject, public Latent typedef bool result_type; template - bool operator() (Iter first, Iter last) const { + result_type operator() (Iter first, Iter last) const { bool r = false; while (first != last) { if (*first) { diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index a278852e77..26432c66ef 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -256,8 +256,8 @@ IO::remove_port (boost::shared_ptr port, void* src) ChanCount after = before; after.set (port->type(), after.get (port->type()) - 1); - bool const r = PortCountChanging (after); /* EMIT SIGNAL */ - if (r) { + boost::optional const r = PortCountChanging (after); /* EMIT SIGNAL */ + if (r.get_value_or (false)) { return -1; } diff --git a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h index 69d1ebdaad..b541582f6f 100644 --- a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h +++ b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include "pbd/signals.h" namespace PBD { class Controllable; @@ -50,7 +50,7 @@ class BindingProxy : public sigc::trackable boost::shared_ptr controllable; guint bind_button; guint bind_statemask; - boost::signals2::scoped_connection learning_connection; + PBD::ScopedConnection learning_connection; void learning_finished (); bool prompter_hiding (GdkEventAny *); }; 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 +#include +#include +#include +#include +#include +#include "pbd/stacktrace.h" + +namespace PBD { + +class Connection; + +class SignalBase : public boost::enable_shared_from_this +{ +public: + virtual ~SignalBase () {} + virtual void disconnect (boost::shared_ptr) = 0; + +protected: + boost::mutex _mutex; +}; + +class Connection : public boost::enable_shared_from_this +{ +public: + Connection (boost::shared_ptr b) : _signal (b) {} + + void disconnect () + { + if (_signal) { + _signal->disconnect (shared_from_this ()); + } + } + +private: + boost::shared_ptr _signal; +}; + +template +class OptionalLastValue +{ +public: + typedef boost::optional result_type; + + template + result_type operator() (Iter first, Iter last) const { + result_type r; + while (first != last) { + r = *first; + ++first; + } + + return r; + } +}; + +template > +class SimpleSignal0 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef boost::optional result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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; + 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 > create () + { + return boost::shared_ptr > (new SimpleSignal0); + } + +private: + + friend class Connection; + + SimpleSignal0 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template <> +class SimpleSignal0 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef void result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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 > create () + { + return boost::shared_ptr > (new SimpleSignal0); + } + +private: + + friend class Connection; + + SimpleSignal0 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template > +class SimpleSignal1 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef boost::optional result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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; + 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 > create () + { + return boost::shared_ptr > (new SimpleSignal1); + } + +private: + + friend class Connection; + + SimpleSignal1 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template +class SimpleSignal1 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef void result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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 > create () + { + return boost::shared_ptr > (new SimpleSignal1); + } + +private: + + friend class Connection; + + SimpleSignal1 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template > +class SimpleSignal2 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef boost::optional result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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; + 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 > create () + { + return boost::shared_ptr > (new SimpleSignal2); + } + +private: + + friend class Connection; + + SimpleSignal2 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template +class SimpleSignal2 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef void result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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 > create () + { + return boost::shared_ptr > (new SimpleSignal2); + } + +private: + + friend class Connection; + + SimpleSignal2 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template > +class SimpleSignal3 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef boost::optional result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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; + 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 > create () + { + return boost::shared_ptr > (new SimpleSignal3); + } + +private: + + friend class Connection; + + SimpleSignal3 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template +class SimpleSignal3 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef void result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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 > create () + { + return boost::shared_ptr > (new SimpleSignal3); + } + +private: + + friend class Connection; + + SimpleSignal3 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template > +class SimpleSignal4 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef boost::optional result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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; + 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 > create () + { + return boost::shared_ptr > (new SimpleSignal4); + } + +private: + + friend class Connection; + + SimpleSignal4 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template +class SimpleSignal4 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef void result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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 > create () + { + return boost::shared_ptr > (new SimpleSignal4); + } + +private: + + friend class Connection; + + SimpleSignal4 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template > +class SimpleSignal5 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef boost::optional result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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; + 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 > create () + { + return boost::shared_ptr > (new SimpleSignal5); + } + +private: + + friend class Connection; + + SimpleSignal5 () {} + + void disconnect (boost::shared_ptr c) + { + boost::mutex::scoped_lock lm (_mutex); + _slots.erase (c); + } +}; + +template +class SimpleSignal5 : public SignalBase +{ +public: + + typedef boost::function slot_function_type; + typedef void result_type; +private: + + + typedef std::map, slot_function_type> Slots; + Slots _slots; + +public: + + + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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 > create () + { + return boost::shared_ptr > (new SimpleSignal5); + } + +private: + + friend class Connection; + + SimpleSignal5 () {} + + void disconnect (boost::shared_ptr 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 ' % 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 +#include +#include +#include +#include +#include +#include "pbd/stacktrace.h" + +namespace PBD { + +class Connection; + +class SignalBase : public boost::enable_shared_from_this +{ +public: + virtual ~SignalBase () {} + virtual void disconnect (boost::shared_ptr) = 0; + +protected: + boost::mutex _mutex; +}; + +class Connection : public boost::enable_shared_from_this +{ +public: + Connection (boost::shared_ptr b) : _signal (b) {} + + void disconnect () + { + if (_signal) { + _signal->disconnect (shared_from_this ()); + } + } + +private: + boost::shared_ptr _signal; +}; + +template +class OptionalLastValue +{ +public: + typedef boost::optional result_type; + + template + 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 "], "typename ") + print >>f,"class SimpleSignal%d : public SignalBase" % n + + print >>f,"{" + print >>f,"public:" + print >>f,"" + if v: + print >>f,"\ttypedef boost::function slot_function_type;" % comma_separated(An) + print >>f,"\ttypedef void result_type;" + else: + print >>f,"\ttypedef boost::function slot_function_type;" % comma_separated(An) + print >>f,"\ttypedef boost::optional result_type;" + + print >>f,"private:" + print >>f,"" + + print >>f,""" + typedef std::map, slot_function_type> Slots; + Slots _slots; +""" + + print >>f,"public:" + print >>f,"" + print >>f,""" + boost::shared_ptr connect (slot_function_type f) + { + boost::shared_ptr 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;" + 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 > create ()" % (n, tp) + print >>f,"\t{" + print >>f,"\t\treturn boost::shared_ptr > (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 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 #include -#include #include #include #include #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 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 class Signal0 { public: - Signal0 () {} - typedef boost::signals2::signal SignalType; + typedef SimpleSignal0 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 _signal; }; -template > +template > class Signal1 { public: - Signal1 () {} - typedef boost::signals2::signal SignalType; + typedef SimpleSignal1 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 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 _signal; }; template class Signal2 { public: - Signal2 () {} - typedef boost::signals2::signal SignalType; + typedef SimpleSignal2 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 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 _signal; }; template class Signal3 { public: - Signal3 () {} - typedef boost::signals2::signal SignalType; + typedef SimpleSignal3 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 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 _signal; }; template class Signal4 { public: - Signal4 () {} - typedef boost::signals2::signal SignalType; + typedef SimpleSignal4 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 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 _signal; }; template class Signal5 { public: - Signal5 () {} - typedef boost::signals2::signal SignalType; + typedef SimpleSignal5 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 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 _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 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 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");