From 02805e3fbdf2bc46e112d8d7f1029c4651079ca1 Mon Sep 17 00:00:00 2001 From: Woowoo678 Date: Fri, 1 Feb 2019 22:09:36 +0100 Subject: [PATCH] Previous Track button behaves incorrectly when in shuffle mode (Bug #13749) --- src/parole-medialist.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++- src/parole-medialist.h | 16 ++++++++ src/parole-player.c | 34 +++++++++++++++-- 3 files changed, 143 insertions(+), 6 deletions(-) diff --git a/src/parole-medialist.c b/src/parole-medialist.c index 9d62859..348e2ea 100644 --- a/src/parole-medialist.c +++ b/src/parole-medialist.c @@ -304,6 +304,8 @@ parole_media_list_add(ParoleMediaList *list, ParoleFile *file, gboolean disc, gb DATA_COL, file, LENGTH_COL, parole_taglibc_get_media_length(file), STATE_COL, PAROLE_MEDIA_STATE_NONE, + PREV_COL, NULL, + NEXT_COL, NULL, -1); if ( emit || select_row ) { @@ -935,6 +937,8 @@ parole_media_list_remove_clicked_cb(GtkButton *button, ParoleMediaList *list) { row = g_list_nth_data(row_list, i); path = gtk_tree_row_reference_get_path(row); + parole_media_list_remove_history(list, row); + if (G_LIKELY(gtk_tree_model_get_iter(model, &iter, path) == TRUE)) { gtk_list_store_remove(GTK_LIST_STORE(model), &iter); @@ -1406,8 +1410,8 @@ parole_media_list_setup_view(ParoleMediaList *list) { GtkListStore *list_store, *disc_list_store; GtkCellRenderer *renderer, *disc_renderer; - list_store = gtk_list_store_new(COL_NUMBERS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT); - disc_list_store = gtk_list_store_new(COL_NUMBERS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT); + list_store = gtk_list_store_new(COL_NUMBERS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT, G_TYPE_POINTER, G_TYPE_POINTER); + disc_list_store = gtk_list_store_new(COL_NUMBERS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT, G_TYPE_POINTER, G_TYPE_POINTER); gtk_tree_view_set_model(GTK_TREE_VIEW(list->priv->view), GTK_TREE_MODEL(list_store)); gtk_tree_view_set_model(GTK_TREE_VIEW(list->priv->disc_view), GTK_TREE_MODEL(disc_list_store)); @@ -2064,3 +2068,94 @@ void parole_media_list_connect_shuffle_action(ParoleMediaList *list, GSimpleActi /* Connect changed event to modify action */ g_signal_connect(G_OBJECT(list->priv->shuffle_button), "clicked", G_CALLBACK(shuffle_toggled), simple); } + +/* + * Link two tracks together in the history chain + */ +void parole_media_list_link_history(ParoleMediaList *list, GtkTreeRowReference *prev_row, GtkTreeRowReference *next_row) { + GtkTreeIter iter; + GtkTreePath *prev_path; + GtkTreePath *next_path; + + if ( !gtk_tree_row_reference_valid(prev_row) && !gtk_tree_row_reference_valid(next_row) ) + return; + + prev_path = gtk_tree_row_reference_get_path(prev_row); + next_path = gtk_tree_row_reference_get_path(next_row); + + if ( ! gtk_tree_path_compare(prev_path, next_path) ) { + /* Make sure we're not forming an infinite history loop */ + TRACE("Trying to link row to itself in history"); + gtk_tree_path_free(prev_path); + gtk_tree_path_free(next_path); + return; + } + + if ( gtk_tree_model_get_iter(GTK_TREE_MODEL(list->priv->store), &iter, prev_path) ) + gtk_list_store_set(list->priv->store, &iter, NEXT_COL, gtk_tree_row_reference_copy(next_row), -1); + + if ( gtk_tree_model_get_iter(GTK_TREE_MODEL(list->priv->store), &iter, next_path)) + gtk_list_store_set(list->priv->store, &iter, PREV_COL, gtk_tree_row_reference_copy(prev_row), -1); + + gtk_tree_path_free(prev_path); + gtk_tree_path_free(next_path); +} + +/* Isolate a given row from its place in the history chain and link together its neighbors */ +void parole_media_list_remove_history(ParoleMediaList *list, GtkTreeRowReference *row) { + GtkTreeRowReference *prev = NULL; + GtkTreeRowReference *next = NULL; + GtkTreeIter iter; + GtkTreePath *path; + + if ( !gtk_tree_row_reference_valid(row) ) + return; + + path = gtk_tree_row_reference_get_path(row); + + if ( gtk_tree_model_get_iter(GTK_TREE_MODEL(list->priv->store), &iter, path) ) { + gtk_tree_model_get(GTK_TREE_MODEL(list->priv->store), &iter, PREV_COL, &prev, -1); + gtk_tree_model_get(GTK_TREE_MODEL(list->priv->store), &iter, NEXT_COL, &next, -1); + + parole_media_list_link_history(list, prev, next); + gtk_list_store_set(list->priv->store, &iter, NEXT_COL, NULL, PREV_COL, NULL, 1); + } + + gtk_tree_row_reference_free(prev); + gtk_tree_row_reference_free(next); + gtk_tree_path_free(path); +} + +GtkTreeRowReference *parole_media_list_get_next_row_by_history(ParoleMediaList *list, GtkTreeRowReference *row) { + GtkTreeRowReference *next = NULL; + GtkTreePath *path; + GtkTreeIter iter; + + if ( !gtk_tree_row_reference_valid (row) ) + return NULL; + + path = gtk_tree_row_reference_get_path(row); + + if ( gtk_tree_model_get_iter(GTK_TREE_MODEL(list->priv->store), &iter, path) ) + gtk_tree_model_get(GTK_TREE_MODEL(list->priv->store), &iter, NEXT_COL, &next, -1); + + gtk_tree_path_free(path); + return next; +} + +GtkTreeRowReference *parole_media_list_get_prev_row_by_history(ParoleMediaList *list, GtkTreeRowReference *row) { + GtkTreeRowReference *next = NULL; + GtkTreePath *path; + GtkTreeIter iter; + + if ( !gtk_tree_row_reference_valid(row) ) + return NULL; + + path = gtk_tree_row_reference_get_path(row); + + if ( gtk_tree_model_get_iter(GTK_TREE_MODEL(list->priv->store), &iter, path) ) + gtk_tree_model_get(GTK_TREE_MODEL(list->priv->store), &iter, PREV_COL, &next, -1); + + gtk_tree_path_free(path); + return next; +} diff --git a/src/parole-medialist.h b/src/parole-medialist.h index cf06ff5..3174589 100644 --- a/src/parole-medialist.h +++ b/src/parole-medialist.h @@ -38,6 +38,8 @@ enum { NAME_COL, LENGTH_COL, DATA_COL, + PREV_COL, + NEXT_COL, COL_NUMBERS }; @@ -192,6 +194,20 @@ parole_media_list_connect_shuffle_action (ParoleMediaList *list, void parole_media_list_add_dvd (ParoleMediaList *list, gchar *dvd_name); +void parole_media_list_link_history (ParoleMediaList *list, + GtkTreeRowReference *prev_row, + GtkTreeRowReference *next_row); + +void parole_media_list_remove_history (ParoleMediaList *list, + GtkTreeRowReference *row); + +GtkTreeRowReference +*parole_media_list_get_next_row_by_history (ParoleMediaList *list, + GtkTreeRowReference *row); + +GtkTreeRowReference +*parole_media_list_get_prev_row_by_history (ParoleMediaList *list, + GtkTreeRowReference *row); G_END_DECLS diff --git a/src/parole-player.c b/src/parole-player.c index 97e9983..4df1666 100644 --- a/src/parole-player.c +++ b/src/parole-player.c @@ -1490,10 +1490,20 @@ parole_player_play_next(ParolePlayer *player, gboolean allow_shuffle) { if ( player->priv->row ) { parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE); - if ( shuffle && allow_shuffle ) - row = parole_media_list_get_row_random(player->priv->list); - else + if ( shuffle && allow_shuffle ) { + /* Before actually shuffling, see if there is history to traverse forward through */ + row = parole_media_list_get_next_row_by_history(player->priv->list, player->priv->row); + if ( !row ) + { + row = parole_media_list_get_row_random(player->priv->list); + /* Break any remaining history links to prevent forming loops */ + parole_media_list_remove_history(player->priv->list, row); + parole_media_list_link_history(player->priv->list, player->priv->row, row); + } + + } else { row = parole_media_list_get_next_row(player->priv->list, player->priv->row, repeat); + } if ( row ) { parole_player_media_activated_cb(player->priv->list, row, player); @@ -1510,6 +1520,7 @@ parole_player_play_next(ParolePlayer *player, gboolean allow_shuffle) { static void parole_player_play_prev(ParolePlayer *player) { + gboolean shuffle; GtkTreeRowReference *row; if ( player->priv->current_media_type == PAROLE_MEDIA_TYPE_DVD ) { @@ -1517,10 +1528,25 @@ parole_player_play_prev(ParolePlayer *player) { return; } + g_object_get(G_OBJECT(player->priv->conf), + "shuffle", &shuffle, + NULL); + if ( player->priv->row ) { parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE); - row = parole_media_list_get_prev_row(player->priv->list, player->priv->row); + if ( shuffle ) { + row = parole_media_list_get_prev_row_by_history(player->priv->list, player->priv->row); + if ( !row ) + { + row = parole_media_list_get_row_random(player->priv->list); + /* Break any remaining history links to prevent forming loops */ + parole_media_list_remove_history(player->priv->list, row); + parole_media_list_link_history(player->priv->list, row, player->priv->row); + } + } else { + row = parole_media_list_get_prev_row(player->priv->list, player->priv->row); + } if ( row ) { parole_player_media_activated_cb(player->priv->list, row, player); -- 2.11.0