Turn AutomationCtrl into a SessionHandleRef
authorRobin Gareus <robin@gareus.org>
Sun, 30 Jul 2017 00:34:14 +0000 (02:34 +0200)
committerRobin Gareus <robin@gareus.org>
Sun, 30 Jul 2017 00:42:55 +0000 (02:42 +0200)
This fixes a crash with GUI elements which are only deleted during GUI
Idle and hold a Reference to a Controllable,
The session is already destroyed at that point:

ARDOUR::CoreSelection::remove_control_by_id(PBD::ID const&)
ARDOUR::AutomationControl::~AutomationControl()
ARDOUR::SlavableAutomationControl::~SlavableAutomationControl()
ARDOUR::MonitorControl::~MonitorControl()
boost::detail::sp_counted_base::destroy()
boost::detail::sp_counted_impl_p<AudioGrapher::Interleaver<float>::Input>::dispose()
boost::detail::sp_counted_base::release()
boost::detail::shared_count::~shared_count()
boost::shared_ptr<PBD::Controllable>::~shared_ptr()
boost::shared_ptr<PBD::Connection>::~shared_ptr()
ArdourWidgets::BindingProxy::~BindingProxy()
ArdourWidgets::ArdourButton::~ArdourButton()
VCAMasterStrip::~VCAMasterStrip()
int idle_delete<VCAMasterStrip>(VCAMasterStrip*)

libs/ardour/ardour/automation_control.h
libs/ardour/automation_control.cc

index 6ffcb3b866cf5dd12c6acac3d1967b1f47eccd2f..e875ea98a6a68fa9eb9a42b63cf87581c0b2b640 100644 (file)
@@ -36,6 +36,7 @@
 #include "ardour/automation_list.h"
 #include "ardour/control_group_member.h"
 #include "ardour/parameter_descriptor.h"
+#include "ardour/session_handle.h"
 
 #include "ardour/libardour_visibility.h"
 
@@ -52,6 +53,7 @@ class LIBARDOUR_API AutomationControl
        , public Evoral::Control
        , public boost::enable_shared_from_this<AutomationControl>
        , public ControlGroupMember
+       , public SessionHandleRef
 {
 public:
        AutomationControl(ARDOUR::Session&,
@@ -124,7 +126,6 @@ public:
        ControlList grouped_controls () const;
 
 protected:
-       ARDOUR::Session& _session;
        boost::shared_ptr<ControlGroup> _group;
 
        const ParameterDescriptor _desc;
@@ -147,6 +148,8 @@ protected:
        /* this will be invoked in turn on behalf of the group or the control by itself */
        virtual void do_pre_realtime_queue_stuff (double new_value) {}
 
+       void session_going_away ();
+
 private:
        /* I am unclear on why we have to make ControlGroup a friend in order
           to get access to the ::set_group() method when it is already
@@ -155,6 +158,7 @@ private:
        friend class ControlGroup;
        void set_group (boost::shared_ptr<ControlGroup>);
        PBD::ScopedConnection _state_changed_connection;
+       bool _no_session;
 };
 
 
index 1c4525470bb018e0db8d2ddc572e11673311f203..7deeac422185e37c44684c5b680d917431d6aae6 100644 (file)
@@ -56,8 +56,9 @@ AutomationControl::AutomationControl(ARDOUR::Session&                          s
 
        : Controllable (name.empty() ? EventTypeMap::instance().to_symbol(parameter) : name, flags)
        , Evoral::Control(parameter, desc, list)
-       , _session(session)
+       , SessionHandleRef (session)
        , _desc(desc)
+       , _no_session(false)
 {
        if (_desc.toggled) {
                set_flags (Controllable::Toggle);
@@ -70,10 +71,18 @@ AutomationControl::AutomationControl(ARDOUR::Session&                          s
 
 AutomationControl::~AutomationControl ()
 {
-       if (!_session.deletion_in_progress ()) {
+       if (!_no_session && !_session.deletion_in_progress ()) {
                _session.selection().remove_control_by_id (id());
+               DropReferences (); /* EMIT SIGNAL */
        }
+}
+
+void
+AutomationControl::session_going_away ()
+{
+       SessionHandleRef::session_going_away ();
        DropReferences (); /* EMIT SIGNAL */
+       _no_session = true;
 }
 
 bool
@@ -90,7 +99,7 @@ AutomationControl::writable() const
 double
 AutomationControl::get_value() const
 {
-       bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
+       bool from_list = alist() && alist()->automation_playback();
        return Control::get_double (from_list, _session.transport_frame());
 }
 
@@ -176,7 +185,7 @@ AutomationControl::automation_run (framepos_t start, pframes_t nframes)
 void
 AutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
 {
-       boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (_list);
+       boost::shared_ptr<AutomationList> al = alist ();
        const framepos_t pos = _session.transport_frame();
        bool to_list;
 
@@ -232,7 +241,7 @@ AutomationControl::set_automation_state (AutoState as)
        if (flags() & NotAutomatable) {
                return;
        }
-       if (_list && as != alist()->automation_state()) {
+       if (alist() && as != alist()->automation_state()) {
 
                const double val = get_value ();