Code

screen_queue: move playlist_save() to save_playlist.c
[ncmpc.git] / src / screen_queue.c
index c5be09af82a7751f2d0670f3eb10c43a3d0f09b1..3d20da3bc999ad10f62e13dfb3a9aa9c7e0471f5 100644 (file)
@@ -1,5 +1,5 @@
 /* ncmpc (Ncurses MPD Client)
- * (c) 2004-2009 The Music Player Daemon Project
+ * (c) 2004-2017 The Music Player Daemon Project
  * Project homepage: http://musicpd.org
  *
  * This program is free software; you can redistribute it and/or modify
@@ -20,8 +20,9 @@
 #include "screen_queue.h"
 #include "screen_interface.h"
 #include "screen_file.h"
-#include "screen_message.h"
+#include "screen_status.h"
 #include "screen_find.h"
+#include "save_playlist.h"
 #include "config.h"
 #include "i18n.h"
 #include "charset.h"
@@ -35,6 +36,7 @@
 #include "screen_utils.h"
 #include "screen_song.h"
 #include "screen_lyrics.h"
+#include "Compiler.h"
 
 #ifndef NCMPC_MINI
 #include "hscroll.h"
@@ -95,22 +97,19 @@ screen_queue_save_selection(void)
 static void
 screen_queue_restore_selection(void)
 {
-       const struct mpd_song *song;
-       int pos;
-
        list_window_set_length(lw, playlist_length(playlist));
 
        if (selected_song_id < 0)
                /* there was no selection */
                return;
 
-       song = screen_queue_selected_song();
+       const struct mpd_song *song = screen_queue_selected_song();
        if (song != NULL &&
            mpd_song_get_id(song) == (unsigned)selected_song_id)
                /* selection is still valid */
                return;
 
-       pos = playlist_get_index_from_id(playlist, selected_song_id);
+       int pos = playlist_get_index_from_id(playlist, selected_song_id);
        if (pos >= 0)
                list_window_set_cursor(lw, pos);
 
@@ -118,15 +117,14 @@ screen_queue_restore_selection(void)
 }
 
 static const char *
-screen_queue_lw_callback(unsigned idx, G_GNUC_UNUSED void *data)
+screen_queue_lw_callback(unsigned idx, gcc_unused void *data)
 {
        static char songname[MAX_SONG_LENGTH];
-       struct mpd_song *song;
 
        assert(playlist != NULL);
        assert(idx < playlist_length(playlist));
 
-       song = playlist_get(playlist, idx);
+       struct mpd_song *song = playlist_get(playlist, idx);
 
        strfsong(songname, MAX_SONG_LENGTH, options.list_format, song);
 
@@ -134,28 +132,18 @@ screen_queue_lw_callback(unsigned idx, G_GNUC_UNUSED void *data)
 }
 
 static void
-center_playing_item(struct mpdclient *c, bool center_cursor)
+center_playing_item(const struct mpd_status *status, bool center_cursor)
 {
-       const struct mpd_song *song;
-       unsigned length = c->playlist.list->len;
-       int idx;
-
-       song = mpdclient_get_current_song(c);
-       if (song == NULL)
+       if (status == NULL ||
+           (mpd_status_get_state(status) != MPD_STATE_PLAY &&
+            mpd_status_get_state(status) != MPD_STATE_PAUSE))
                return;
 
        /* try to center the song that are playing */
-       idx = playlist_get_index(&c->playlist, c->song);
+       int idx = mpd_status_get_song_pos(status);
        if (idx < 0)
                return;
 
-       if (length < lw->rows)
-       {
-               if (center_cursor)
-                       list_window_set_cursor(lw, idx);
-               return;
-       }
-
        list_window_center(lw, idx);
 
        if (center_cursor) {
@@ -167,31 +155,31 @@ center_playing_item(struct mpdclient *c, bool center_cursor)
        list_window_fetch_cursor(lw);
 }
 
-#ifndef NCMPC_MINI
-static void
-save_pre_completion_cb(GCompletion *gcmp, G_GNUC_UNUSED gchar *line,
-                      void *data)
+gcc_pure
+static int
+get_current_song_id(const struct mpd_status *status)
 {
-       completion_callback_data_t *tmp = (completion_callback_data_t *)data;
-       GList **list = tmp->list;
-       struct mpdclient *c = tmp->c;
-
-       if( *list == NULL ) {
-               /* create completion list */
-               *list = gcmp_list_from_path(c, "", NULL, GCMP_TYPE_PLAYLIST);
-               g_completion_add_items(gcmp, *list);
-       }
+       return status != NULL &&
+               (mpd_status_get_state(status) == MPD_STATE_PLAY ||
+                mpd_status_get_state(status) == MPD_STATE_PAUSE)
+               ? (int)mpd_status_get_song_id(status)
+               : -1;
 }
 
-static void
-save_post_completion_cb(G_GNUC_UNUSED GCompletion *gcmp,
-                       G_GNUC_UNUSED gchar *line, GList *items,
-                       G_GNUC_UNUSED void *data)
+static bool
+screen_queue_song_change(const struct mpd_status *status)
 {
-       if (g_list_length(items) >= 1)
-               screen_display_completion_list(items);
+       if (get_current_song_id(status) == current_song_id)
+               return false;
+
+       current_song_id = get_current_song_id(status);
+
+       /* center the cursor */
+       if (options.auto_center && !lw->range_selection)
+               center_playing_item(status, false);
+
+       return true;
 }
-#endif
 
 #ifndef NCMPC_MINI
 /**
@@ -206,106 +194,6 @@ completion_strncmp(const gchar *s1, const gchar *s2, gsize n)
 }
 #endif
 
-int
-playlist_save(struct mpdclient *c, char *name, char *defaultname)
-{
-       struct mpd_connection *connection;
-       gchar *filename, *filename_utf8;
-#ifndef NCMPC_MINI
-       GCompletion *gcmp;
-       GList *list = NULL;
-       completion_callback_data_t data;
-#endif
-
-#ifdef NCMPC_MINI
-       (void)defaultname;
-#endif
-
-#ifndef NCMPC_MINI
-       if (name == NULL) {
-               /* initialize completion support */
-               gcmp = g_completion_new(NULL);
-               g_completion_set_compare(gcmp, completion_strncmp);
-               data.list = &list;
-               data.dir_list = NULL;
-               data.c = c;
-               wrln_completion_callback_data = &data;
-               wrln_pre_completion_callback = save_pre_completion_cb;
-               wrln_post_completion_callback = save_post_completion_cb;
-
-
-               /* query the user for a filename */
-               filename = screen_readln(_("Save playlist as"),
-                                        defaultname,
-                                        NULL,
-                                        gcmp);
-
-               /* destroy completion support */
-               wrln_completion_callback_data = NULL;
-               wrln_pre_completion_callback = NULL;
-               wrln_post_completion_callback = NULL;
-               g_completion_free(gcmp);
-               list = string_list_free(list);
-               if( filename )
-                       filename=g_strstrip(filename);
-       } else
-#endif
-                       filename=g_strdup(name);
-
-       if (filename == NULL)
-               return -1;
-
-       /* send save command to mpd */
-
-       connection = mpdclient_get_connection(c);
-       if (connection == NULL)
-               return -1;
-
-       filename_utf8 = locale_to_utf8(filename);
-       if (!mpd_run_save(connection, filename_utf8)) {
-               if (mpd_connection_get_error(connection) == MPD_ERROR_SERVER &&
-                   mpd_connection_get_server_error(connection) == MPD_SERVER_ERROR_EXIST &&
-                   mpd_connection_clear_error(connection)) {
-                       char *buf;
-                       int key;
-
-                       buf = g_strdup_printf(_("Replace %s [%s/%s] ? "),
-                                             filename, YES, NO);
-                       key = tolower(screen_getch(buf));
-                       g_free(buf);
-
-                       if (key != YES[0]) {
-                               g_free(filename_utf8);
-                               g_free(filename);
-                               screen_status_printf(_("Aborted"));
-                               return -1;
-                       }
-
-                       if (!mpd_run_rm(connection, filename_utf8) ||
-                           !mpd_run_save(connection, filename_utf8)) {
-                               mpdclient_handle_error(c);
-                               g_free(filename_utf8);
-                               g_free(filename);
-                               return -1;
-                       }
-               } else {
-                       mpdclient_handle_error(c);
-                       g_free(filename_utf8);
-                       g_free(filename);
-                       return -1;
-               }
-       }
-
-       c->events |= MPD_IDLE_STORED_PLAYLIST;
-
-       g_free(filename_utf8);
-
-       /* success */
-       screen_status_printf(_("Saved %s"), filename);
-       g_free(filename);
-       return 0;
-}
-
 #ifndef NCMPC_MINI
 static void add_dir(GCompletion *gcmp, gchar *dir, GList **dir_list,
                    GList **list, struct mpdclient *c)
@@ -357,34 +245,31 @@ static void add_post_completion_cb(GCompletion *gcmp, gchar *line,
 static int
 handle_add_to_playlist(struct mpdclient *c)
 {
-       gchar *path;
 #ifndef NCMPC_MINI
-       GCompletion *gcmp;
+       /* initialize completion support */
+       GCompletion *gcmp = g_completion_new(NULL);
+       g_completion_set_compare(gcmp, completion_strncmp);
+
        GList *list = NULL;
        GList *dir_list = NULL;
-       completion_callback_data_t data;
+       completion_callback_data_t data = {
+               .list = &list,
+               .dir_list = &dir_list,
+               .c = c,
+       };
 
-       /* initialize completion support */
-       gcmp = g_completion_new(NULL);
-       g_completion_set_compare(gcmp, completion_strncmp);
-       data.list = &list;
-       data.dir_list = &dir_list;
-       data.c = c;
        wrln_completion_callback_data = &data;
        wrln_pre_completion_callback = add_pre_completion_cb;
        wrln_post_completion_callback = add_post_completion_cb;
+#else
+       GCompletion *gcmp = NULL;
 #endif
 
        /* get path */
-       path = screen_readln(_("Add"),
-                            NULL,
-                            NULL,
-#ifdef NCMPC_MINI
-                            NULL
-#else
-                            gcmp
-#endif
-                            );
+       char *path = screen_readln(_("Add"),
+                                  NULL,
+                                  NULL,
+                                  gcmp);
 
        /* destroy completion data */
 #ifndef NCMPC_MINI
@@ -408,7 +293,7 @@ handle_add_to_playlist(struct mpdclient *c)
 }
 
 static void
-screen_queue_init(WINDOW *w, int cols, int rows)
+screen_queue_init(WINDOW *w, unsigned cols, unsigned rows)
 {
        lw = list_window_init(w, cols, rows);
 
@@ -435,8 +320,8 @@ timer_hide_cursor(gpointer data)
                lw->hide_cursor = true;
                screen_queue_repaint();
        } else
-               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
-                                                    timer_hide_cursor, c);
+               timer_hide_cursor_id = g_timeout_add_seconds(options.hide_cursor,
+                                                            timer_hide_cursor, c);
 
        return FALSE;
 }
@@ -449,11 +334,12 @@ screen_queue_open(struct mpdclient *c)
        assert(timer_hide_cursor_id == 0);
        if (options.hide_cursor > 0) {
                lw->hide_cursor = false;
-               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
-                                                    timer_hide_cursor, c);
+               timer_hide_cursor_id = g_timeout_add_seconds(options.hide_cursor,
+                                                            timer_hide_cursor, c);
        }
 
        screen_queue_restore_selection();
+       screen_queue_song_change(c->status);
 }
 
 static void
@@ -471,7 +357,7 @@ screen_queue_close(void)
 }
 
 static void
-screen_queue_resize(int cols, int rows)
+screen_queue_resize(unsigned cols, unsigned rows)
 {
        list_window_resize(lw, cols, rows);
 }
@@ -487,35 +373,31 @@ static const char *
 screen_queue_title(char *str, size_t size)
 {
        if (options.host == NULL)
-               return _("Playlist");
+               return _("Queue");
 
-       g_snprintf(str, size, _("Playlist on %s"), options.host);
+       g_snprintf(str, size, _("Queue on %s"), options.host);
        return str;
 }
 
 static void
 screen_queue_paint_callback(WINDOW *w, unsigned i,
                            unsigned y, unsigned width,
-                           bool selected, G_GNUC_UNUSED void *data)
+                           bool selected, gcc_unused const void *data)
 {
-       const struct mpd_song *song;
-       struct hscroll *row_hscroll;
-
        assert(playlist != NULL);
        assert(i < playlist_length(playlist));
 
-       song = playlist_get(playlist, i);
+       const struct mpd_song *song = playlist_get(playlist, i);
 
-#ifdef NCMPC_MINI
-       row_hscroll = NULL;
-#else
+       struct hscroll *row_hscroll = NULL;
+#ifndef NCMPC_MINI
        row_hscroll = selected && options.scroll && lw->selected == i
                ? &hscroll : NULL;
 #endif
 
        paint_song_row(w, y, width, selected,
                       (int)mpd_song_get_id(song) == current_song_id,
-                      song, row_hscroll);
+                      song, row_hscroll, options.list_format);
 }
 
 static void
@@ -529,50 +411,33 @@ screen_queue_paint(void)
        list_window_paint2(lw, screen_queue_paint_callback, NULL);
 }
 
-G_GNUC_PURE
-static int
-get_current_song_id(const struct mpd_status *status)
-{
-       return status != NULL &&
-               (mpd_status_get_state(status) == MPD_STATE_PLAY ||
-                mpd_status_get_state(status) == MPD_STATE_PAUSE)
-               ? (int)mpd_status_get_song_id(status)
-               : -1;
-}
-
 static void
 screen_queue_update(struct mpdclient *c)
 {
-       if (c->events & MPD_IDLE_PLAYLIST)
+       if (c->events & MPD_IDLE_QUEUE)
                screen_queue_restore_selection();
+       else
+               /* the queue size may have changed, even if we havn't
+                  received the QUEUE idle event yet */
+               list_window_set_length(lw, playlist_length(playlist));
 
-       if ((c->events & MPD_IDLE_PLAYER) != 0 &&
-           get_current_song_id(c->status) != current_song_id) {
-               current_song_id = get_current_song_id(c->status);
-
-               /* center the cursor */
-               if (options.auto_center && current_song_id != -1 && ! lw->range_selection)
-                       center_playing_item(c, false);
-
-               screen_queue_repaint();
-       } else if (c->events & MPD_IDLE_PLAYLIST) {
-               /* the playlist has changed, we must paint the new
-                  version */
-               screen_queue_repaint();
-       }
+       if (((c->events & MPD_IDLE_PLAYER) != 0 &&
+            screen_queue_song_change(c->status)) ||
+           c->events & MPD_IDLE_QUEUE)
+               /* the queue or the current song has changed, we must
+                  paint the new version */
+               screen_queue_paint();
 }
 
 #ifdef HAVE_GETMOUSE
 static bool
 handle_mouse_event(struct mpdclient *c)
 {
-       int row;
        unsigned long bstate;
-       unsigned old_selected;
-
+       int row;
        if (screen_get_mouse_event(c, &bstate, &row) ||
            list_window_mouse(lw, bstate, row)) {
-               screen_queue_repaint();
+               screen_queue_paint();
                return true;
        }
 
@@ -582,7 +447,7 @@ handle_mouse_event(struct mpdclient *c)
                return true;
        }
 
-       old_selected = lw->selected;
+       const unsigned old_selected = lw->selected;
        list_window_set_cursor(lw, lw->start + row);
 
        if (bstate & BUTTON1_CLICKED) {
@@ -606,7 +471,7 @@ handle_mouse_event(struct mpdclient *c)
        }
 
        screen_queue_save_selection();
-       screen_queue_repaint();
+       screen_queue_paint();
 
        return true;
 }
@@ -617,10 +482,8 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
 {
        struct mpd_connection *connection;
        static command_t cached_cmd = CMD_NONE;
-       command_t prev_cmd = cached_cmd;
-       struct list_window_range range;
-       const struct mpd_song *song;
 
+       const command_t prev_cmd = cached_cmd;
        cached_cmd = cmd;
 
        lw->hide_cursor = false;
@@ -628,26 +491,26 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
        if (options.hide_cursor > 0) {
                if (timer_hide_cursor_id != 0)
                        g_source_remove(timer_hide_cursor_id);
-               timer_hide_cursor_id = g_timeout_add(options.hide_cursor * 1000,
-                                                    timer_hide_cursor, c);
+               timer_hide_cursor_id = g_timeout_add_seconds(options.hide_cursor,
+                                                            timer_hide_cursor, c);
        }
 
        if (list_window_cmd(lw, cmd)) {
                screen_queue_save_selection();
-               screen_queue_repaint();
+               screen_queue_paint();
                return true;
        }
 
        switch(cmd) {
        case CMD_SCREEN_UPDATE:
-               center_playing_item(c, prev_cmd == CMD_SCREEN_UPDATE);
-               screen_queue_repaint();
+               center_playing_item(c->status, prev_cmd == CMD_SCREEN_UPDATE);
+               screen_queue_paint();
                return false;
        case CMD_SELECT_PLAYING:
                list_window_set_cursor(lw, playlist_get_index(&c->playlist,
                                                              c->song));
                screen_queue_save_selection();
-               screen_queue_repaint();
+               screen_queue_paint();
                return true;
 
        case CMD_LIST_FIND:
@@ -656,12 +519,12 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
        case CMD_LIST_RFIND_NEXT:
                screen_find(lw, cmd, screen_queue_lw_callback, NULL);
                screen_queue_save_selection();
-               screen_queue_repaint();
+               screen_queue_paint();
                return true;
        case CMD_LIST_JUMP:
-               screen_jump(lw, screen_queue_lw_callback, NULL, NULL);
+               screen_jump(lw, screen_queue_lw_callback, NULL, NULL, NULL);
                screen_queue_save_selection();
-               screen_queue_repaint();
+               screen_queue_paint();
                return true;
 
 #ifdef HAVE_GETMOUSE
@@ -697,7 +560,10 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
                break;
 #endif
        case CMD_SCREEN_SWAP:
-               screen_swap(c, playlist_get(&c->playlist, lw->selected));
+               if (playlist_length(&c->playlist) > 0)
+                       screen_swap(c, playlist_get(&c->playlist, lw->selected));
+               else
+                       screen_swap(c, NULL);
                return true;
 
        default:
@@ -708,6 +574,9 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
                return false;
 
        switch(cmd) {
+               const struct mpd_song *song;
+               struct list_window_range range;
+
        case CMD_PLAY:
                song = screen_queue_selected_song();
                if (song == NULL)
@@ -737,7 +606,7 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
 
        case CMD_SHUFFLE:
                list_window_get_range(lw, &range);
-               if (range.end < range.start + 1)
+               if (range.end <= range.start + 1)
                        /* No range selection, shuffle all list. */
                        break;
 
@@ -746,7 +615,7 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
                        return true;
 
                if (mpd_run_shuffle_range(connection, range.start, range.end))
-                       screen_status_message(_("Shuffled playlist"));
+                       screen_status_message(_("Shuffled queue"));
                else
                        mpdclient_handle_error(c);
                return true;
@@ -762,6 +631,10 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
                lw->selected--;
                lw->range_base--;
 
+               if (lw->range_selection)
+                       list_window_scroll_to(lw, lw->range_base);
+               list_window_scroll_to(lw, lw->selected);
+
                screen_queue_save_selection();
                return true;
 
@@ -776,6 +649,10 @@ screen_queue_cmd(struct mpdclient *c, command_t cmd)
                lw->selected++;
                lw->range_base++;
 
+               if (lw->range_selection)
+                       list_window_scroll_to(lw, lw->range_base);
+               list_window_scroll_to(lw, lw->selected);
+
                screen_queue_save_selection();
                return true;