~alextee/zrythm-devel

add error reporting to all undoable actions (WIP) v1 APPLIED

Alexandros Theodotou: 1
 add error reporting to all undoable actions (WIP)

 11 files changed, 306 insertions(+), 195 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~alextee/zrythm-devel/patches/24252/mbox | git am -3
Learn more about email & git

[PATCH] add error reporting to all undoable actions (WIP) Export this patch

---
 inc/actions/arranger_selections.h     | 101 +++++++-----
 inc/actions/channel_send_action.h     |  30 ++--
 inc/actions/midi_mapping_action.h     |  19 ++-
 inc/actions/mixer_selections_action.h |  32 ++--
 inc/actions/port_action.h             |  14 +-
 inc/actions/range_action.h            |  21 ++-
 inc/actions/tracklist_selections.h    |   6 +-
 inc/actions/transport_action.h        |  16 +-
 inc/actions/undoable_action.h         |  10 +-
 src/actions/arranger_selections.c     | 222 ++++++++++++++++----------
 src/actions/undoable_action.c         |  30 ++--
 11 files changed, 306 insertions(+), 195 deletions(-)

diff --git a/inc/actions/arranger_selections.h b/inc/actions/arranger_selections.h
index 652b1f099..825c8f326 100644
--- a/inc/actions/arranger_selections.h
+++ b/inc/actions/arranger_selections.h
@@ -415,23 +415,25 @@ arranger_selections_action_init_loaded (
UndoableAction *
arranger_selections_action_new_create_or_delete (
  ArrangerSelections * sel,
  const bool           create);
  const bool           create,
  GError **            error);

#define \
arranger_selections_action_new_create(sel) \
arranger_selections_action_new_create(sel,error) \
  arranger_selections_action_new_create_or_delete ( \
    (ArrangerSelections *) sel, true)
    (ArrangerSelections *) sel, true, error)

#define \
arranger_selections_action_new_delete(sel) \
arranger_selections_action_new_delete(sel,error) \
  arranger_selections_action_new_create_or_delete ( \
    (ArrangerSelections *) sel, false)
    (ArrangerSelections *) sel, false, error)

UndoableAction *
arranger_selections_action_new_record (
  ArrangerSelections * sel_before,
  ArrangerSelections * sel_after,
  const bool           already_recorded);
  const bool           already_recorded,
  GError **            error);

/**
 * Creates a new action for moving or duplicating
@@ -454,7 +456,8 @@ arranger_selections_action_new_move_or_duplicate (
  const int            delta_tracks,
  const int            delta_lanes,
  const double         delta_normalized_amount,
  const bool           already_moved);
  const bool           already_moved,
  GError **            error);

/**
 * Creates a new action for linking regions.
@@ -471,74 +474,81 @@ arranger_selections_action_new_link (
  const double         ticks,
  const int            delta_tracks,
  const int            delta_lanes,
  const bool           already_moved);
  const bool           already_moved,
  GError **            error);

#define \
arranger_selections_action_new_move( \
  sel,ticks,chords,pitch,tracks,lanes,norm_amt, \
  already_moved) \
  already_moved,error) \
  arranger_selections_action_new_move_or_duplicate ( \
    (ArrangerSelections *) sel, 1, ticks, chords, \
    pitch, tracks, lanes, norm_amt, already_moved)
    pitch, tracks, lanes, norm_amt, already_moved, \
    error)

#define \
arranger_selections_action_new_duplicate( \
  sel,ticks,chords,pitch,tracks,lanes,norm_amt, \
  already_moved) \
  already_moved,error) \
  arranger_selections_action_new_move_or_duplicate ( \
    (ArrangerSelections *) sel, 0, ticks, chords, \
    pitch, tracks, lanes, norm_amt, already_moved)
    pitch, tracks, lanes, norm_amt, already_moved, \
    error)

#define \
arranger_selections_action_new_move_timeline( \
  sel,ticks,delta_tracks,delta_lanes, \
  already_moved) \
  already_moved,error) \
  arranger_selections_action_new_move ( \
    sel, ticks, 0, 0, delta_tracks, delta_lanes, \
    0, already_moved)
    0, already_moved, error)
#define \
arranger_selections_action_new_duplicate_timeline( \
  sel,ticks,delta_tracks,delta_lanes, \
  already_moved) \
  already_moved,error) \
  arranger_selections_action_new_duplicate ( \
    sel, ticks, 0, 0, delta_tracks, delta_lanes, \
    0, already_moved)
    0, already_moved, error)

#define \
arranger_selections_action_new_move_midi( \
  sel,ticks,delta_pitch, already_moved) \
  sel,ticks,delta_pitch,already_moved,error) \
  arranger_selections_action_new_move ( \
    sel, ticks, 0, delta_pitch, 0, 0, \
    0, already_moved)
    0, already_moved, error)
#define \
arranger_selections_action_new_duplicate_midi( \
  sel,ticks,delta_pitch,already_moved) \
  sel,ticks,delta_pitch,already_moved,error) \
  arranger_selections_action_new_duplicate ( \
    sel, ticks, 0, delta_pitch, 0, 0, \
    0, already_moved)
    0, already_moved, error)

#define \
arranger_selections_action_new_move_chord( \
  sel,ticks,delta_chords, already_moved) \
  sel,ticks,delta_chords,already_moved,error) \
  arranger_selections_action_new_move ( \
    sel, ticks, delta_chords, 0, 0, 0, \
    0, already_moved)
    0, already_moved, error)
#define \
arranger_selections_action_new_duplicate_chord( \
  sel,ticks,delta_chords, already_moved) \
  sel,ticks,delta_chords,already_moved,error) \
  arranger_selections_action_new_duplicate ( \
    sel, ticks, delta_chords, 0, 0, 0, \
    0, already_moved)
    0, already_moved, error)

#define \
arranger_selections_action_new_move_automation( \
  sel,ticks,norm_amt,already_moved) \
  sel,ticks,norm_amt,already_moved,error) \
  arranger_selections_action_new_move ( \
    sel, ticks, 0, 0, 0, 0, norm_amt, already_moved)
    sel, ticks, 0, 0, 0, 0, norm_amt, \
    already_moved, error)

#define \
arranger_selections_action_new_duplicate_automation( \
  sel,ticks,norm_amt,already_moved) \
  sel,ticks,norm_amt,already_moved,error) \
  arranger_selections_action_new_duplicate ( \
    sel, ticks, 0, 0, 0, 0, norm_amt, already_moved)
    sel, ticks, 0, 0, 0, 0, norm_amt, \
    already_moved, error)

/**
 * Creates a new action for editing properties
@@ -555,7 +565,8 @@ arranger_selections_action_new_edit (
  ArrangerSelections *             sel_before,
  ArrangerSelections *             sel_after,
  ArrangerSelectionsActionEditType type,
  bool                             already_edited);
  bool                             already_edited,
  GError **                        error);

/**
 * Wrapper over
@@ -565,7 +576,8 @@ arranger_selections_action_new_edit (
UndoableAction *
arranger_selections_action_new_edit_midi_function (
  ArrangerSelections * sel_before,
  MidiFunctionType     midi_func_type);
  MidiFunctionType     midi_func_type,
  GError **            error);

/**
 * Wrapper over
@@ -574,8 +586,9 @@ arranger_selections_action_new_edit_midi_function (
 */
UndoableAction *
arranger_selections_action_new_edit_automation_function (
  ArrangerSelections * sel_before,
  AutomationFunctionType automation_func_type);
  ArrangerSelections *   sel_before,
  AutomationFunctionType automation_func_type,
  GError **              error);

/**
 * Wrapper over
@@ -586,7 +599,8 @@ UndoableAction *
arranger_selections_action_new_edit_audio_function (
  ArrangerSelections * sel_before,
  AudioFunctionType    audio_func_type,
  const char *         uri);
  const char *         uri,
  GError **            error);

/**
 * Creates a new action for automation autofill.
@@ -602,7 +616,8 @@ UndoableAction *
arranger_selections_action_new_automation_fill (
  ZRegion * region_before,
  ZRegion * region_after,
  bool      already_changed);
  bool      already_changed,
  GError ** error);

/**
 * Creates a new action for splitting
@@ -613,7 +628,8 @@ arranger_selections_action_new_automation_fill (
UndoableAction *
arranger_selections_action_new_split (
  ArrangerSelections * sel,
  const Position *     pos);
  const Position *     pos,
  GError **            error);

/**
 * Creates a new action for merging
@@ -621,7 +637,8 @@ arranger_selections_action_new_split (
 */
UndoableAction *
arranger_selections_action_new_merge (
  ArrangerSelections * sel);
  ArrangerSelections * sel,
  GError **            error);

/**
 * Creates a new action for resizing
@@ -634,7 +651,8 @@ UndoableAction *
arranger_selections_action_new_resize (
  ArrangerSelections *               sel,
  ArrangerSelectionsActionResizeType type,
  const double                       ticks);
  const double                       ticks,
  GError **                          error);

/**
 * Creates a new action fro quantizing
@@ -645,15 +663,18 @@ arranger_selections_action_new_resize (
UndoableAction *
arranger_selections_action_new_quantize (
  ArrangerSelections * sel,
  QuantizeOptions *    opts);
  QuantizeOptions *    opts,
  GError **            error);

int
arranger_selections_action_do (
  ArrangerSelectionsAction * self);
  ArrangerSelectionsAction * self,
  GError **                  error);

int
arranger_selections_action_undo (
  ArrangerSelectionsAction * self);
  ArrangerSelectionsAction * self,
  GError **                  error);

char *
arranger_selections_action_stringize (
diff --git a/inc/actions/channel_send_action.h b/inc/actions/channel_send_action.h
index 07c1f9da2..d272a285f 100644
--- a/inc/actions/channel_send_action.h
+++ b/inc/actions/channel_send_action.h
@@ -114,44 +114,48 @@ channel_send_action_new (
  ChannelSendActionType type,
  Port *                port,
  StereoPorts *         stereo,
  float                 amount);
  float                 amount,
  GError **             error);

#define channel_send_action_new_disconnect(send) \
#define channel_send_action_new_disconnect( \
  send,error) \
  channel_send_action_new ( \
    send, CHANNEL_SEND_ACTION_DISCONNECT, NULL, NULL, \
    0.f)
    0.f, error)

#define channel_send_action_new_connect_midi( \
  send,midi) \
  send,midi,error) \
  channel_send_action_new ( \
    send, CHANNEL_SEND_ACTION_CONNECT_MIDI, midi, \
    NULL, 0.f)
    NULL, 0.f, error)

#define channel_send_action_new_connect_audio( \
  send,stereo) \
  send,stereo,error) \
  channel_send_action_new ( \
    send, CHANNEL_SEND_ACTION_CONNECT_STEREO, NULL, \
    stereo, 0.f)
    stereo, 0.f, error)

#define channel_send_action_new_connect_sidechain( \
  send,stereo) \
  send,stereo,error) \
  channel_send_action_new ( \
    send, CHANNEL_SEND_ACTION_CONNECT_SIDECHAIN, \
    NULL, stereo, 0.f)
    NULL, stereo, 0.f, error)

#define channel_send_action_new_change_amount( \
  send,amt) \
  send,amt,error) \
  channel_send_action_new ( \
    send, CHANNEL_SEND_ACTION_CHANGE_AMOUNT, NULL, \
    NULL, amt)
    NULL, amt, error)

int
channel_send_action_do (
  ChannelSendAction * self);
  ChannelSendAction * self,
  GError **           error);

int
channel_send_action_undo (
  ChannelSendAction * self);
  ChannelSendAction * self,
  GError **           error);

char *
channel_send_action_stringize (
diff --git a/inc/actions/midi_mapping_action.h b/inc/actions/midi_mapping_action.h
index a6a58685e..1047b31e4 100644
--- a/inc/actions/midi_mapping_action.h
+++ b/inc/actions/midi_mapping_action.h
@@ -1,5 +1,5 @@
/*
 * Copyright (C) 2020 Alexandros Theodotou <alex at zrythm dot org>
 * Copyright (C) 2020-2021 Alexandros Theodotou <alex at zrythm dot org>
 *
 * This file is part of Zrythm
 *
@@ -109,8 +109,9 @@ midi_mapping_action_init_loaded (
 */
UndoableAction *
midi_mapping_action_new_enable (
  int  idx,
  bool enable);
  int       idx,
  bool      enable,
  GError ** error);

/**
 * Creates a new action.
@@ -119,22 +120,26 @@ UndoableAction *
midi_mapping_action_new_bind (
  midi_byte_t *  buf,
  ExtPort *      device_port,
  Port *         dest_port);
  Port *         dest_port,
  GError **      error);

/**
 * Creates a new action.
 */
UndoableAction *
midi_mapping_action_new_unbind (
  int            idx);
  int       idx,
  GError ** error);

int
midi_mapping_action_do (
  MidiMappingAction * self);
  MidiMappingAction * self,
  GError **           error);

int
midi_mapping_action_undo (
  MidiMappingAction * self);
  MidiMappingAction * self,
  GError **           error);

char *
midi_mapping_action_stringize (
diff --git a/inc/actions/mixer_selections_action.h b/inc/actions/mixer_selections_action.h
index d7b527aaa..75d6f397a 100644
--- a/inc/actions/mixer_selections_action.h
+++ b/inc/actions/mixer_selections_action.h
@@ -193,44 +193,50 @@ mixer_selections_action_new (
  int                       to_track_pos,
  int                       to_slot,
  PluginSetting *           setting,
  int                       num_plugins);
  int                       num_plugins,
  GError **                 error);

#define mixer_selections_action_new_create( \
  slot_type,to_tr,to_slot,setting,num_plugins) \
  slot_type,to_tr,to_slot,setting,num_plugins, \
  error) \
  mixer_selections_action_new ( \
    NULL, MIXER_SELECTIONS_ACTION_CREATE, \
    slot_type, to_tr, to_slot, setting, num_plugins)
    slot_type, to_tr, to_slot, setting, \
    num_plugins, error)

#define mixer_selections_action_new_copy( \
  ms,slot_type,to_tr,to_slot) \
  ms,slot_type,to_tr,to_slot,error) \
  mixer_selections_action_new ( \
    ms, MIXER_SELECTIONS_ACTION_COPY, slot_type, \
    to_tr, to_slot, NULL, 0)
    to_tr, to_slot, NULL, 0, error)

#define mixer_selections_action_new_paste( \
  ms,slot_type,to_tr,to_slot) \
  ms,slot_type,to_tr,to_slot,error) \
  mixer_selections_action_new ( \
    ms, MIXER_SELECTIONS_ACTION_PASTE, slot_type, \
    to_tr, to_slot, NULL, 0)
    to_tr, to_slot, NULL, 0, error)

#define mixer_selections_action_new_move( \
  ms,slot_type,to_tr,to_slot) \
  ms,slot_type,to_tr,to_slot,error) \
  mixer_selections_action_new ( \
    ms, MIXER_SELECTIONS_ACTION_MOVE, slot_type, \
    to_tr, to_slot, NULL, 0)
    to_tr, to_slot, NULL, 0, error)

#define mixer_selections_action_new_delete(ms) \
#define mixer_selections_action_new_delete( \
  ms,error) \
  mixer_selections_action_new ( \
    ms, MIXER_SELECTIONS_ACTION_DELETE, 0, \
    0, 0, NULL, 0)
    0, 0, NULL, 0, error)

int
mixer_selections_action_do (
  MixerSelectionsAction * self);
  MixerSelectionsAction * self,
  GError **               error);

int
mixer_selections_action_undo (
  MixerSelectionsAction * self);
  MixerSelectionsAction * self,
  GError **               error);

char *
mixer_selections_action_stringize (
diff --git a/inc/actions/port_action.h b/inc/actions/port_action.h
index 3cfd49498..4ee51d4ee 100644
--- a/inc/actions/port_action.h
+++ b/inc/actions/port_action.h
@@ -1,5 +1,5 @@
/*
 * Copyright (C) 2020 Alexandros Theodotou <alex at zrythm dot org>
 * Copyright (C) 2020-2021 Alexandros Theodotou <alex at zrythm dot org>
 *
 * This file is part of Zrythm
 *
@@ -94,7 +94,8 @@ port_action_init_loaded (
 */
UndoableAction *
port_action_new_reset_control (
  PortIdentifier * port_id);
  PortIdentifier * port_id,
  GError **        error);

/**
 * Create a new action.
@@ -104,15 +105,18 @@ port_action_new (
  PortActionType   type,
  PortIdentifier * port_id,
  float            val,
  bool             is_normalized);
  bool             is_normalized,
  GError **        error);

int
port_action_do (
  PortAction * self);
  PortAction * self,
  GError **    error);

int
port_action_undo (
  PortAction * self);
  PortAction * self,
  GError **    error);

char *
port_action_stringize (
diff --git a/inc/actions/range_action.h b/inc/actions/range_action.h
index b3673792a..777bef861 100644
--- a/inc/actions/range_action.h
+++ b/inc/actions/range_action.h
@@ -1,5 +1,5 @@
/*
 * Copyright (C) 2020 Alexandros Theodotou <alex at zrythm dot org>
 * Copyright (C) 2020-2021 Alexandros Theodotou <alex at zrythm dot org>
 *
 * This file is part of Zrythm
 *
@@ -126,22 +126,27 @@ UndoableAction *
range_action_new (
  RangeActionType type,
  Position *      start_pos,
  Position *      end_pos);
  Position *      end_pos,
  GError **       error);

#define range_action_new_insert_silence(start,end) \
#define range_action_new_insert_silence( \
  start,end,error) \
  range_action_new ( \
    RANGE_ACTION_INSERT_SILENCE, start, end)
    RANGE_ACTION_INSERT_SILENCE, start, end, error)

#define range_action_new_remove(start,end) \
  range_action_new (RANGE_ACTION_REMOVE, start, end)
#define range_action_new_remove(start,end,error) \
  range_action_new ( \
    RANGE_ACTION_REMOVE, start, end, error)

int
range_action_do (
  RangeAction * self);
  RangeAction * self,
  GError **     error);

int
range_action_undo (
  RangeAction * self);
  RangeAction * self,
  GError **     error);

char *
range_action_stringize (
diff --git a/inc/actions/tracklist_selections.h b/inc/actions/tracklist_selections.h
index 0eef49643..db67325f1 100644
--- a/inc/actions/tracklist_selections.h
+++ b/inc/actions/tracklist_selections.h
@@ -694,11 +694,13 @@ tracklist_selections_action_new (

int
tracklist_selections_action_do (
  TracklistSelectionsAction * self);
  TracklistSelectionsAction * self,
  GError **                   error);

int
tracklist_selections_action_undo (
  TracklistSelectionsAction * self);
  TracklistSelectionsAction * self,
  GError **                   error);

char *
tracklist_selections_action_stringize (
diff --git a/inc/actions/transport_action.h b/inc/actions/transport_action.h
index bf96e4e88..6c47650b8 100644
--- a/inc/actions/transport_action.h
+++ b/inc/actions/transport_action.h
@@ -112,24 +112,28 @@ transport_action_init_loaded (

UndoableAction *
transport_action_new_bpm_change (
  bpm_t           bpm_before,
  bpm_t           bpm_after,
  bool            already_done);
  bpm_t     bpm_before,
  bpm_t     bpm_after,
  bool      already_done,
  GError ** error);

UndoableAction *
transport_action_new_time_sig_change (
  TransportActionType type,
  int                 before,
  int                 after,
  bool                already_done);
  bool                already_done,
  GError **           error);

int
transport_action_do (
  TransportAction * self);
  TransportAction * self,
  GError **         error);

int
transport_action_undo (
  TransportAction * self);
  TransportAction * self,
  GError **         error);

char *
transport_action_stringize (
diff --git a/inc/actions/undoable_action.h b/inc/actions/undoable_action.h
index d106a88a7..bf92d24e2 100644
--- a/inc/actions/undoable_action.h
+++ b/inc/actions/undoable_action.h
@@ -206,20 +206,22 @@ undoable_action_set_num_actions (
 *
 * @return Non-zero if errors occurred.
 */
NONNULL
NONNULL_ARGS (1)
int
undoable_action_do (
  UndoableAction * self);
  UndoableAction * self,
  GError **        error);

/**
 * Undoes the action.
 *
 * @return Non-zero if errors occurred.
 */
NONNULL
NONNULL_ARGS (1)
int
undoable_action_undo (
  UndoableAction * self);
  UndoableAction * self,
  GError **        error);

void
undoable_action_free (
diff --git a/src/actions/arranger_selections.c b/src/actions/arranger_selections.c
index 284612e2d..4f8f2c70e 100644
--- a/src/actions/arranger_selections.c
+++ b/src/actions/arranger_selections.c
@@ -43,6 +43,17 @@

#include <glib/gi18n.h>

typedef enum
{
  Z_ACTIONS_ARRANGER_SELECTIONS_ERROR_FAILED,
} ZActionsArrangerSelectionsError;

#define Z_ACTIONS_ARRANGER_SELECTIONS_ERROR \
  z_actions_arranger_selections_error_quark ()
GQuark z_actions_arranger_selections_error_quark (void);
G_DEFINE_QUARK (
  z-actions-arranger-selections-error-quark, z_actions_arranger_selections_error)

static void
move_obj_by_tracks_and_lanes (
  ArrangerObject * obj,
@@ -239,34 +250,6 @@ free_split_objects (
  self->region_r2[i] = NULL;
}

#if 0
static void
set_single_object (
  ArrangerSelectionsAction * self,
  ArrangerObject *           obj)
{
  self->obj = obj;

  switch (obj->type)
    {
    case ARRANGER_OBJECT_TYPE_REGION:
      self->region = (ZRegion *) obj;
      break;
    case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
      self->midi_note = (MidiNote *) obj;
      break;
    case ARRANGER_OBJECT_TYPE_SCALE_OBJECT:
      self->scale = (ScaleObject *) obj;
      break;
    case ARRANGER_OBJECT_TYPE_MARKER:
      self->marker = (Marker *) obj;
      break;
    default:
      g_return_if_reached ();
    }
}
#endif

static ArrangerSelectionsAction *
_create_action (
  ArrangerSelections * sel)
@@ -335,7 +318,8 @@ arranger_selections_action_new_move_or_duplicate (
  const int            delta_tracks,
  const int            delta_lanes,
  const double         delta_normalized_amount,
  const bool           already_moved)
  const bool           already_moved,
  GError **            error)
{
  g_return_val_if_fail (
    IS_ARRANGER_SELECTIONS (sel) &&
@@ -385,7 +369,8 @@ arranger_selections_action_new_link (
  const double         ticks,
  const int            delta_tracks,
  const int            delta_lanes,
  const bool           already_moved)
  const bool           already_moved,
  GError **            error)
{
  g_return_val_if_fail (
    sel_before && sel_after, NULL);
@@ -416,7 +401,8 @@ arranger_selections_action_new_link (
UndoableAction *
arranger_selections_action_new_create_or_delete (
  ArrangerSelections * sel,
  const bool           create)
  const bool           create,
  GError **            error)
{
  g_return_val_if_fail (
    IS_ARRANGER_SELECTIONS (sel) &&
@@ -425,9 +411,12 @@ arranger_selections_action_new_create_or_delete (
  if (arranger_selections_contains_undeletable_object (
        sel))
    {
      g_warning (
        "attempted to delete an undeletable "
        "object");
      g_set_error (
        error, Z_ACTIONS_ARRANGER_SELECTIONS_ERROR,
        Z_ACTIONS_ARRANGER_SELECTIONS_ERROR_FAILED,
        "%s",
        _("Arranger selections contain an "
          "undeletable object"));
      return NULL;
    }

@@ -450,7 +439,8 @@ UndoableAction *
arranger_selections_action_new_record (
  ArrangerSelections * sel_before,
  ArrangerSelections * sel_after,
  const bool           already_recorded)
  const bool           already_recorded,
  GError **            error)
{
  ArrangerSelectionsAction * self =
    _create_action (sel_before);
@@ -480,7 +470,8 @@ arranger_selections_action_new_edit (
  ArrangerSelections *             sel_before,
  ArrangerSelections *             sel_after,
  ArrangerSelectionsActionEditType type,
  bool                             already_edited)
  bool                             already_edited,
  GError **                        error)
{
  ArrangerSelectionsAction * self =
    _create_action (sel_before);
@@ -527,11 +518,24 @@ arranger_selections_action_new_edit (
UndoableAction *
arranger_selections_action_new_edit_midi_function (
  ArrangerSelections * sel_before,
  MidiFunctionType     midi_func_type)
  MidiFunctionType     midi_func_type,
  GError **            error)
{
  ArrangerSelections * sel_after =
    arranger_selections_clone (sel_before);
  midi_function_apply (sel_after, midi_func_type);

  GError * err = NULL;
  int ret =
    midi_function_apply (
      sel_after, midi_func_type, &err);
  if (ret != 0)
    {
      PROPAGATE_PREFIXED_ERROR (
        error, err, "%s",
        _("Failed to apply MIDI function"));
      arranger_selections_free_full (sel_after);
      return NULL;
    }

  UndoableAction * ua =
    arranger_selections_action_new_edit (
@@ -551,13 +555,25 @@ arranger_selections_action_new_edit_midi_function (
 */
UndoableAction *
arranger_selections_action_new_edit_automation_function (
  ArrangerSelections * sel_before,
  AutomationFunctionType automation_func_type)
  ArrangerSelections *   sel_before,
  AutomationFunctionType automation_func_type,
  GError **              error)
{
  ArrangerSelections * sel_after =
    arranger_selections_clone (sel_before);
  automation_function_apply (
    sel_after, automation_func_type);

  GError * err = NULL;
  int ret =
    automation_function_apply (
      sel_after, automation_func_type, &err);
  if (ret != 0)
    {
      PROPAGATE_PREFIXED_ERROR (
        error, err, "%s",
        _("Failed to apply automation function"));
      arranger_selections_free_full (sel_after);
      return NULL;
    }

  UndoableAction * ua =
    arranger_selections_action_new_edit (
@@ -579,7 +595,8 @@ UndoableAction *
arranger_selections_action_new_edit_audio_function (
  ArrangerSelections * sel_before,
  AudioFunctionType    audio_func_type,
  const char *         uri)
  const char *         uri,
  GError **            error)
{
  /* prepare selections before */
  ArrangerSelections * sel_before_clone =
@@ -592,10 +609,10 @@ arranger_selections_action_new_edit_audio_function (
    audio_function_apply (
      sel_before_clone, AUDIO_FUNCTION_INVALID,
      NULL, &err);
  if (res != 0)
  if (ret != 0)
    {
      HANDLE_ERROR (
        err, "%s",
      PROPAGATE_PREFIXED_ERROR (
        error, err, "%s",
        _("Failed to apply audio function"));
      arranger_selections_free_full (
        sel_before_clone);
@@ -610,8 +627,8 @@ arranger_selections_action_new_edit_audio_function (
      sel_after, audio_func_type, uri, &err);
  if (res != 0)
    {
      HANDLE_ERROR (
        err, "%s",
      PROPAGATE_PREFIXED_ERROR (
        error, err, "%s",
        _("Failed to apply audio function"));
      arranger_selections_free_full (sel_after);
      return NULL;
@@ -643,7 +660,8 @@ UndoableAction *
arranger_selections_action_new_automation_fill (
  ZRegion * region_before,
  ZRegion * region_after,
  bool      already_changed)
  bool      already_changed,
  GError ** error)
{
  ArrangerSelectionsAction * self =
    object_new (ArrangerSelectionsAction);
@@ -682,7 +700,8 @@ arranger_selections_action_new_automation_fill (
UndoableAction *
arranger_selections_action_new_split (
  ArrangerSelections * sel,
  const Position *     pos)
  const Position *     pos,
  GError **            error)
{
  ArrangerSelectionsAction * self =
    _create_action (sel);
@@ -705,7 +724,8 @@ arranger_selections_action_new_split (
 */
UndoableAction *
arranger_selections_action_new_merge (
  ArrangerSelections * sel)
  ArrangerSelections * sel,
  GError **            error)
{
  ArrangerSelectionsAction * self =
    _create_action (sel);
@@ -726,7 +746,8 @@ UndoableAction *
arranger_selections_action_new_resize (
  ArrangerSelections *               sel,
  ArrangerSelectionsActionResizeType type,
  const double                       ticks)
  const double                       ticks,
  GError **                          error)
{
  /* validate */
  bool have_unresizable =
@@ -734,7 +755,16 @@ arranger_selections_action_new_resize (
      sel,
      ARRANGER_SELECTIONS_PROPERTY_HAS_LENGTH,
      false);
  g_return_val_if_fail (!have_unresizable, NULL);
  if (have_unresizable)
    {
      g_set_error (
        error, Z_ACTIONS_ARRANGER_SELECTIONS_ERROR,
        Z_ACTIONS_ARRANGER_SELECTIONS_ERROR_FAILED,
        "%s",
        _("Attempted to resize unresizable "
          "objects"));
      return NULL;
    }

  bool have_looped =
    arranger_selections_contains_object_with_property (
@@ -755,9 +785,11 @@ arranger_selections_action_new_resize (
       type
         == ARRANGER_SELECTIONS_ACTION_STRETCH_R))
    {
      g_critical (
        "cannot perform %s resize - selections "
        "contain looped objects",
      g_set_error (
        error, Z_ACTIONS_ARRANGER_SELECTIONS_ERROR,
        Z_ACTIONS_ARRANGER_SELECTIONS_ERROR_FAILED,
        _("Cannot perform %s resize - selections "
        "contain looped objects"),
        arranger_selections_action_resize_type_strings[type].str);
      return NULL;
    }
@@ -775,9 +807,11 @@ arranger_selections_action_new_resize (
       type
         == ARRANGER_SELECTIONS_ACTION_RESIZE_R_LOOP))
    {
      g_critical (
        "cannot perform %s resize - selections "
        "contain unloopable objects",
      g_set_error (
        error, Z_ACTIONS_ARRANGER_SELECTIONS_ERROR,
        Z_ACTIONS_ARRANGER_SELECTIONS_ERROR_FAILED,
        _("Cannot perform %s resize - selections "
        "contain unloopable objects"),
        arranger_selections_action_resize_type_strings[type].str);
      return NULL;
    }
@@ -802,7 +836,8 @@ arranger_selections_action_new_resize (
UndoableAction *
arranger_selections_action_new_quantize (
  ArrangerSelections * sel,
  QuantizeOptions *    opts)
  QuantizeOptions *    opts,
  GError **            error)
{
  ArrangerSelectionsAction * self =
    _create_action (sel);
@@ -849,7 +884,8 @@ update_region_link_groups (
static int
do_or_undo_move (
  ArrangerSelectionsAction * self,
  const bool                 _do)
  const bool                 _do,
  GError **                  error)
{
  int size = 0;
  arranger_selections_sort_by_indices (
@@ -1152,7 +1188,8 @@ static int
do_or_undo_duplicate_or_link (
  ArrangerSelectionsAction * self,
  const bool                 link,
  const bool                 _do)
  const bool                 _do,
  GError **                  error)
{
  arranger_selections_sort_by_indices (
    self->sel, !_do);
@@ -1658,7 +1695,8 @@ static int
do_or_undo_create_or_delete (
  ArrangerSelectionsAction * self,
  const int                  _do,
  const int                  create)
  const int                  create,
  GError **                  error)
{
  int size = 0;
  if (create)
@@ -1850,7 +1888,8 @@ do_or_undo_create_or_delete (
static int
do_or_undo_record (
  ArrangerSelectionsAction * self,
  const bool                 _do)
  const bool                 _do,
  GError **                  error)
{
  int size_before = 0;
  int size_after = 0;
@@ -2012,7 +2051,8 @@ do_or_undo_record (
static int
do_or_undo_edit (
  ArrangerSelectionsAction * self,
  const int                  _do)
  const int                  _do,
  GError **                  error)
{
  int size = 0;
  ArrangerObject ** objs_before =
@@ -2272,7 +2312,8 @@ do_or_undo_edit (
static int
do_or_undo_automation_fill (
  ArrangerSelectionsAction * self,
  const int                  _do)
  const int                  _do,
  GError **                  error)
{
  if (!self->first_run)
    {
@@ -2347,7 +2388,8 @@ do_or_undo_automation_fill (
static int
do_or_undo_split (
  ArrangerSelectionsAction * self,
  const int                  _do)
  const int                  _do,
  GError **                  error)
{
  int size = 0;
  ArrangerObject ** objs =
@@ -2431,7 +2473,8 @@ do_or_undo_split (
static int
do_or_undo_merge (
  ArrangerSelectionsAction * self,
  const bool                 _do)
  const bool                 _do,
  GError **                  error)
{
  /* if first run, merge */
  if (self->first_run)
@@ -2510,7 +2553,8 @@ do_or_undo_merge (
static int
do_or_undo_resize (
  ArrangerSelectionsAction * self,
  const int                  _do)
  const int                  _do,
  GError **                  error)
{
  int size = 0;
  ArrangerObject ** objs =
@@ -2602,7 +2646,8 @@ do_or_undo_resize (
static int
do_or_undo_quantize (
  ArrangerSelectionsAction * self,
  const int                  _do)
  const int                  _do,
  GError **                  error)
{
  int size = 0;
  ArrangerObject ** objs =
@@ -2686,50 +2731,51 @@ do_or_undo_quantize (
static int
do_or_undo (
  ArrangerSelectionsAction * self,
  bool                       _do)
  bool                       _do,
  GError **                  error)
{
  switch (self->type)
    {
    case AS_ACTION_CREATE:
      return
        do_or_undo_create_or_delete (
          self, _do, true);
          self, _do, true, error);
      break;
    case AS_ACTION_DELETE:
      return
        do_or_undo_create_or_delete (
          self, _do, false);
          self, _do, false, error);
      break;
    case AS_ACTION_DUPLICATE:
      return
        do_or_undo_duplicate_or_link (
          self, false, _do);
          self, false, _do, error);
    case AS_ACTION_MOVE:
      return do_or_undo_move (self, _do);
      return do_or_undo_move (self, _do, error);
    case AS_ACTION_LINK:
      return
        do_or_undo_duplicate_or_link (
          self, true, _do);
          self, true, _do, error);
    case AS_ACTION_RECORD:
      return do_or_undo_record (self, _do);
      return do_or_undo_record (self, _do, error);
      break;
    case AS_ACTION_EDIT:
      return do_or_undo_edit (self, _do);
      return do_or_undo_edit (self, _do, error);
      break;
    case AS_ACTION_AUTOMATION_FILL:
      return do_or_undo_automation_fill (
        self, _do);
        self, _do, error);
    case AS_ACTION_SPLIT:
      return do_or_undo_split (self, _do);
      return do_or_undo_split (self, _do, error);
      break;
    case AS_ACTION_MERGE:
      return do_or_undo_merge (self, _do);
      return do_or_undo_merge (self, _do, error);
      break;
    case AS_ACTION_RESIZE:
      return do_or_undo_resize (self, _do);
      return do_or_undo_resize (self, _do, error);
      break;
    case AS_ACTION_QUANTIZE:
      return do_or_undo_quantize (self, _do);
      return do_or_undo_quantize (self, _do, error);
      break;
    default:
      break;
@@ -2739,16 +2785,18 @@ do_or_undo (

int
arranger_selections_action_do (
  ArrangerSelectionsAction * self)
  ArrangerSelectionsAction * self,
  GError **                  error)
{
  return do_or_undo (self, true);
  return do_or_undo (self, true, error);
}

int
arranger_selections_action_undo (
  ArrangerSelectionsAction * self)
  ArrangerSelectionsAction * self,
  GError **                  error)
{
  return do_or_undo (self, false);
  return do_or_undo (self, false, error);
}

bool
diff --git a/src/actions/undoable_action.c b/src/actions/undoable_action.c
index 6bcd15a7a..ad6206d55 100644
--- a/src/actions/undoable_action.c
+++ b/src/actions/undoable_action.c
@@ -241,7 +241,9 @@ undoable_action_can_contain_clip (
 * @return Non-zero if errors occurred.
 */
int
undoable_action_do (UndoableAction * self)
undoable_action_do (
  UndoableAction * self,
  GError **        error)
{
#if 0
  g_debug ("waiting for port operation lock...");
@@ -268,7 +270,9 @@ undoable_action_do (UndoableAction * self)
        undoable_action_to_string (self); \
      g_message ( \
        "[DOING ACTION]: " #uc " (%s)", str); \
      ret = sc##_action_do ((cc##Action *) self); \
      ret = \
        sc##_action_do ( \
          (cc##Action *) self, error); \
      if (ret == 0) \
        { \
          g_message ("[DONE]: " #uc " (%s)", str); \
@@ -337,10 +341,12 @@ undoable_action_do (UndoableAction * self)
/**
 * Undoes the action.
 *
 * Note: only to be called by undo manager.
 * @return Non-zero if errors occurred.
 */
int
undoable_action_undo (UndoableAction * self)
undoable_action_undo (
  UndoableAction * self,
  GError **        error);
{
  /*zix_sem_wait (&AUDIO_ENGINE->port_operation_lock);*/

@@ -364,11 +370,17 @@ undoable_action_undo (UndoableAction * self)
      g_message ( \
        "[UNDOING ACTION]: " #uc " (%s)", str); \
      ret = \
        sc##_action_undo ((cc##Action *) self); \
        sc##_action_do ( \
          (cc##Action *) self, error); \
      if (ret == 0) \
        { \
          g_message ("[UNDONE]: " #uc " (%s)", str); \
        } \
      else \
        { \
          g_warning ( \
            "[FAILED]: " #uc " (%s)", str); \
        } \
      g_free (str); \
    } \
    break;
@@ -376,12 +388,10 @@ undoable_action_undo (UndoableAction * self)
  switch (self->type)
    {
    UNDO_ACTION (
      TRACKLIST_SELECTIONS,
      tracklist_selections,
      TRACKLIST_SELECTIONS, tracklist_selections,
      TracklistSelections);
    UNDO_ACTION (CHANNEL_SEND,
               channel_send,
               ChannelSend);
    UNDO_ACTION (
      CHANNEL_SEND, channel_send, ChannelSend);
    UNDO_ACTION (
      MIXER_SELECTIONS, mixer_selections,
      MixerSelections);
-- 
2.24.3 (Apple Git-128)