Use main editor for loop-range undo/redo - fix crash

While CueEditor is-a HistoryOwner, session specific
changes such as Location don't belong in EditingContext.

This fixes a heap-use-after-free crash since MementoCommand
was free()ed twice. Once via ARDOUR::Location::~Location
and earlier due to direct Destructible::drop_references
from the History.

This partially reverts 04a8fb1eb6
This commit is contained in:
Robin Gareus 2025-08-20 21:16:31 +02:00
parent 8bfd8de2f6
commit 4b88330c9c
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
6 changed files with 39 additions and 37 deletions

View file

@ -35,6 +35,7 @@
#include "cue_editor.h" #include "cue_editor.h"
#include "editor_drag.h" #include "editor_drag.h"
#include "gui_thread.h" #include "gui_thread.h"
#include "public_editor.h"
#include "timers.h" #include "timers.h"
#include "ui_config.h" #include "ui_config.h"
@ -562,7 +563,7 @@ CueEditor::loop_button_press (GdkEventButton* ev)
if (_session->get_play_loop()) { if (_session->get_play_loop()) {
_session->request_play_loop (false); _session->request_play_loop (false);
} else { } else {
set_loop_range (_region->position(), _region->end(), _("loop region")); PublicEditor::instance().set_loop_range (_region->position(), _region->end(), _("loop region"));
_session->request_play_loop (true); _session->request_play_loop (true);
} }

View file

@ -3475,40 +3475,6 @@ EditingContext::transport_loop_location()
} }
} }
void
EditingContext::set_loop_range (timepos_t const & start, timepos_t const & end, string cmd)
{
EC_LOCAL_TEMPO_SCOPE;
if (!_session) {
return;
}
if (_session->get_play_loop () && _session->actively_recording ()) {
return;
}
begin_reversible_command (cmd);
Location* tll;
if ((tll = transport_loop_location()) == 0) {
Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
XMLNode &before = _session->locations()->get_state();
_session->locations()->add (loc, true);
_session->set_auto_loop_location (loc);
XMLNode &after = _session->locations()->get_state();
add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
} else {
XMLNode &before = tll->get_state();
tll->set_hidden (false, this);
tll->set (start, end);
XMLNode &after = tll->get_state();
add_command (new MementoCommand<Location>(*tll, &before, &after));
}
commit_reversible_command ();
}
bool bool
EditingContext::allow_trim_cursors () const EditingContext::allow_trim_cursors () const
{ {

View file

@ -481,8 +481,6 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider,
virtual void update_grid (); virtual void update_grid ();
void set_loop_range (Temporal::timepos_t const & start, Temporal::timepos_t const & end, std::string cmd);
virtual bool allow_trim_cursors () const; virtual bool allow_trim_cursors () const;
virtual void make_a_region() {} virtual void make_a_region() {}

View file

@ -4072,6 +4072,41 @@ Editor::_get_preferred_edit_position (EditIgnoreOption ignore, bool from_context
return where; return where;
} }
void
Editor::set_loop_range (timepos_t const & start, timepos_t const & end, string cmd)
{
if (!_session) {
return;
}
if (_session->get_play_loop () && _session->actively_recording ()) {
return;
}
begin_reversible_command (cmd);
Location* tll;
if ((tll = transport_loop_location()) == 0) {
Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
XMLNode &before = _session->locations()->get_state();
_session->locations()->add (loc, true);
_session->set_auto_loop_location (loc);
XMLNode &after = _session->locations()->get_state();
add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
} else if (tll->start() != start || tll->end () != end){
XMLNode &before = tll->get_state();
tll->set_hidden (false, this);
tll->set (start, end);
XMLNode &after = tll->get_state();
add_command (new MementoCommand<Location>(*tll, &before, &after));
} else {
abort_reversible_command ();
return;
}
commit_reversible_command ();
}
void void
Editor::set_punch_range (timepos_t const & start, timepos_t const & end, string cmd) Editor::set_punch_range (timepos_t const & start, timepos_t const & end, string cmd)
{ {

View file

@ -1413,6 +1413,7 @@ private:
void set_loop_from_region (bool play); void set_loop_from_region (bool play);
void set_loop_range (Temporal::timepos_t const & start, Temporal::timepos_t const & end, std::string cmd);
void set_punch_range (Temporal::timepos_t const & start, Temporal::timepos_t const & end, std::string cmd); void set_punch_range (Temporal::timepos_t const & start, Temporal::timepos_t const & end, std::string cmd);
void add_tempo_from_playhead_cursor (); void add_tempo_from_playhead_cursor ();

View file

@ -192,6 +192,7 @@ public:
} }
virtual void add_location_mark_with_flag (Temporal::timepos_t const & where, ARDOUR::Location::Flags, int32_t cue_id) = 0; virtual void add_location_mark_with_flag (Temporal::timepos_t const & where, ARDOUR::Location::Flags, int32_t cue_id) = 0;
virtual void remove_tracks () = 0; virtual void remove_tracks () = 0;
virtual void set_loop_range (Temporal::timepos_t const & start, Temporal::timepos_t const & end, std::string cmd) = 0;
virtual void set_punch_range (Temporal::timepos_t const & start, Temporal::timepos_t const & end, std::string cmd) = 0; virtual void set_punch_range (Temporal::timepos_t const & start, Temporal::timepos_t const & end, std::string cmd) = 0;
void jump_forward_to_mark () { void jump_forward_to_mark () {