Skip to content

Commit

Permalink
fix crash when holding down ctrl-d for a long time (~alextee/zrythm-b…
Browse files Browse the repository at this point in the history
…ug#114)
  • Loading branch information
alex-tee committed Jan 17, 2021
1 parent 3427a53 commit 75e6ee6
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 17 deletions.
21 changes: 21 additions & 0 deletions inc/utils/arrays.h
Expand Up @@ -104,6 +104,27 @@
} \
}

/**
* Deletes element from array and rearranges other
* elements accordingly.
*/
#define array_delete_confirm( \
array,size,element,confirm) \
confirm = false; \
for (size_t ii = 0; ii < (size_t) size; ii++) \
{ \
if ((void *) array[ii] == (void *) element) \
{ \
confirm = true; \
--size; \
for (size_t jj = ii; jj < (size_t) size; jj++) \
{ \
array[jj] = array[jj + 1]; \
} \
break; \
} \
}

/**
* Deletes element from array and rearranges other
* elements accordingly.
Expand Down
7 changes: 4 additions & 3 deletions src/actions/actions.c
Expand Up @@ -1140,9 +1140,10 @@ activate_delete (
}

void
activate_duplicate (GSimpleAction *action,
GVariant *variant,
gpointer user_data)
activate_duplicate (
GSimpleAction *action,
GVariant *variant,
gpointer user_data)
{
ArrangerSelections * sel =
main_window_get_last_focused_arranger_selections (
Expand Down
2 changes: 1 addition & 1 deletion src/actions/undo_manager.c
Expand Up @@ -90,7 +90,7 @@ undo_manager_undo (UndoManager * self)
undo_stack_pop_last (
self->redo_stack);

/* TODO create functions to delet eunnecessary
/* TODO create functions to delete unnecessary
* files held by the action (eg, something
* that calls plugin_delete_state_files()) */
undoable_action_free (action_to_delete);
Expand Down
26 changes: 16 additions & 10 deletions src/actions/undo_stack.c
Expand Up @@ -195,22 +195,23 @@ undo_stack_push (
}
}

static int
static bool
remove_action (
UndoStack * self,
UndoableAction * action)
{
/* CAPS, CamelCase, snake_case */
#define REMOVE_ELEMENT(caps,cc,sc) \
case UA_##caps: \
array_delete ( \
array_delete_confirm ( \
self->sc##_actions, \
self->num_##sc##_actions, \
(cc##Action *) action); \
removed = 1; \
(cc##Action *) action, \
removed); \
g_warn_if_fail (removed); \
break

int removed = 0;
bool removed = false;
switch (action->type)
{
REMOVE_ELEMENT (
Expand All @@ -233,14 +234,15 @@ remove_action (
REMOVE_ELEMENT (
TRANSPORT, Transport, transport);
case UA_ARRANGER_SELECTIONS:
array_delete (
array_delete_confirm (
self->as_actions,
self->num_as_actions,
(ArrangerSelectionsAction *) action);
removed = 1;
(ArrangerSelectionsAction *) action,
removed);
g_warn_if_fail (removed);
g_warn_if_fail (
(int) self->num_as_actions <=
self->stack->top + 1);
g_atomic_int_get (&self->stack->top) + 1);
break;
}

Expand Down Expand Up @@ -270,12 +272,16 @@ UndoableAction *
undo_stack_pop_last (
UndoStack * self)
{
g_message (
"<undo stack> popping last (top = %d)",
g_atomic_int_get (&self->stack->top));

/* pop from stack */
UndoableAction * action =
(UndoableAction *) stack_pop_last (self->stack);

/* remove the action */
int removed = remove_action (self, action);
bool removed = remove_action (self, action);
g_warn_if_fail (removed);

/* return it */
Expand Down
9 changes: 6 additions & 3 deletions src/gui/backend/arranger_selections.c
Expand Up @@ -17,6 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include <limits.h>
#include <math.h>
#include <stdlib.h>

Expand Down Expand Up @@ -775,6 +776,7 @@ add_region_ticks (
{
ArrangerObject * obj =
arranger_selections_get_first_object (self);
g_return_if_fail (obj);
ArrangerObject * region =
(ArrangerObject *)
arranger_object_get_region (obj);
Expand Down Expand Up @@ -803,8 +805,8 @@ arranger_selections_get_start_pos (
MidiArrangerSelections * mas;
AutomationSelections * as;

position_set_to_bar (
pos, TRANSPORT->total_bars);
position_set_to_bar (pos, INT_MAX);
/*&pos, TRANSPORT->total_bars);*/

#define GET_START_POS(sel,cc,sc) \
for (i = 0; i < (sel)->num_##sc##s; i++) \
Expand Down Expand Up @@ -1034,7 +1036,8 @@ arranger_selections_get_first_object (

Position pos;
position_set_to_bar (
&pos, TRANSPORT->total_bars);
/*&pos, TRANSPORT->total_bars);*/
&pos, INT_MAX);
ArrangerObject * ret_obj = NULL;

#define GET_FIRST_OBJ(sel,cc,sc) \
Expand Down
138 changes: 138 additions & 0 deletions tests/actions/undo_manager.c
@@ -0,0 +1,138 @@
/*
* Copyright (C) 2021 Alexandros Theodotou <alex at zrythm dot org>
*
* This file is part of Zrythm
*
* Zrythm is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Zrythm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
*/

#include "zrythm-test-config.h"

#include <math.h>

#include "actions/undo_manager.h"
#include "project.h"
#include "utils/flags.h"
#include "zrythm.h"

#include "tests/helpers/project.h"
#include "tests/helpers/zrythm.h"

#include <glib.h>
#include <locale.h>

static void
perform_create_region_action ()
{
Position p1, p2;
position_set_to_bar (&p1, 1);
position_set_to_bar (&p2, 2);
int track_pos = TRACKLIST->num_tracks - 1;
ZRegion * r =
midi_region_new (
&p1, &p2, track_pos, 0, 0);
ArrangerObject * r_obj =
(ArrangerObject *) r;
track_add_region (
TRACKLIST->tracks[track_pos],
r, NULL, 0, F_GEN_NAME,
F_NO_PUBLISH_EVENTS);
arranger_object_select (
r_obj, F_SELECT, F_NO_APPEND);
UndoableAction * ua =
arranger_selections_action_new_create (
(ArrangerSelections *) TL_SELECTIONS);
undo_manager_perform (UNDO_MANAGER, ua);
}

static void
test_perform_many_actions ()
{
test_helper_zrythm_init ();

for (int i = 0;
!undo_stack_is_full (UNDO_MANAGER->undo_stack);
i++)
{
UndoableAction * ua = NULL;
if (i % 2 == 0)
{
ua =
tracklist_selections_action_new_create_midi (
TRACKLIST->num_tracks, 1);
undo_manager_perform (UNDO_MANAGER, ua);
}
else if (i % 13 == 0)
{
undo_manager_undo (UNDO_MANAGER);
}
else if (i % 17 == 0)
{
test_project_save_and_reload ();
}
else
{
perform_create_region_action ();
}
}
UndoableAction * ua =
tracklist_selections_action_new_create_midi (
TRACKLIST->num_tracks, 1);
undo_manager_perform (UNDO_MANAGER, ua);
perform_create_region_action ();
perform_create_region_action ();

for (int i = 0;
!undo_stack_is_full (
UNDO_MANAGER->redo_stack) ||
undo_stack_is_empty (
UNDO_MANAGER->redo_stack);
i++)
{
if (undo_stack_is_empty (
UNDO_MANAGER->redo_stack))
{
break;
}

if (i % 17 == 0)
{
test_project_save_and_reload ();
}
else if (i % 47 == 0)
{
perform_create_region_action ();
}
else
{
undo_manager_redo (UNDO_MANAGER);
}
}

test_helper_zrythm_cleanup ();
}

int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);

#define TEST_PREFIX "/actions/undo manager/"

g_test_add_func (
TEST_PREFIX "test perform many actions",
(GTestFunc) test_perform_many_actions);

return g_test_run ();
}
96 changes: 96 additions & 0 deletions tests/gui/backend/arranger_selections.c
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2021 Alexandros Theodotou <alex at zrythm dot org>
*
* This file is part of Zrythm
*
* Zrythm is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Zrythm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
*/

#include "zrythm-test-config.h"

#include <math.h>

#include "audio/midi_region.h"
#include "gui/backend/arranger_selections.h"
#include "project.h"
#include "utils/flags.h"
#include "zrythm.h"

#include "tests/helpers/zrythm.h"

#include <glib.h>
#include <locale.h>

static void
test_region_length_in_ticks (
Track * track,
int bar_start,
int bar_end)
{
Position p1, p2;
position_set_to_bar (&p1, bar_start);
position_set_to_bar (&p2, bar_end);
ZRegion * r =
midi_region_new (
&p1, &p2, track->pos, 0, 0);
ArrangerObject * r_obj = (ArrangerObject *) r;
track_add_region (
track, r, NULL, 0, F_GEN_NAME,
F_NO_PUBLISH_EVENTS);

arranger_object_select (
r_obj, F_SELECT, F_NO_APPEND);

double length =
arranger_selections_get_length_in_ticks (
(ArrangerSelections *) TL_SELECTIONS);
g_assert_cmpfloat_with_epsilon (
length,
TRANSPORT->ticks_per_bar * (bar_end - bar_start),
0.00001);
}

static void
test_get_length_in_ticks ()
{
test_helper_zrythm_init ();

UndoableAction * ua =
tracklist_selections_action_new_create_midi (
TRACKLIST->num_tracks, 1);
undo_manager_perform (UNDO_MANAGER, ua);

Track * track =
TRACKLIST->tracks[TRACKLIST->num_tracks - 1];

test_region_length_in_ticks (track, 3, 4);
test_region_length_in_ticks (track, 100, 102);
test_region_length_in_ticks (track, 1000, 1010);

test_helper_zrythm_cleanup ();
}

int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);

#define TEST_PREFIX "/gui/backend/arranger selections/"

g_test_add_func (
TEST_PREFIX "test get length in ticks",
(GTestFunc) test_get_length_in_ticks);

return g_test_run ();
}

0 comments on commit 75e6ee6

Please sign in to comment.