X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fscreen_lyrics.c;h=11786c1a9e778ee503983645e468a8b63760a4fd;hb=b316776ac8db6d6d874f611ecca64b0a5ddeeb02;hp=a8c721068542563a57713d8c1503733b0e07fac5;hpb=c64c37477b87ec545365b8923d6f9ff745469617;p=ncmpc.git diff --git a/src/screen_lyrics.c b/src/screen_lyrics.c index a8c7210..11786c1 100644 --- a/src/screen_lyrics.c +++ b/src/screen_lyrics.c @@ -1,5 +1,5 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2010 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 @@ -28,9 +28,13 @@ #include "screen.h" #include "lyrics.h" #include "screen_text.h" +#include "screen_utils.h" +#include "ncu.h" #include +#include #include +#include #include #include #include @@ -41,6 +45,8 @@ static struct screen_text text; static struct mpd_song *next_song; static bool follow = false; +/** Set if the cursor position shall be kept during the next lyrics update. */ +static bool reloading = false; static struct { struct mpd_song *song; @@ -111,10 +117,9 @@ static bool exists_lyr_file(const char *artist, const char *title) { char path[1024]; - struct stat result; - path_lyr_file(path, 1024, artist, title); + struct stat result; return (stat(path, &result) == 0); } @@ -122,7 +127,6 @@ static FILE * create_lyr_file(const char *artist, const char *title) { char path[1024]; - snprintf(path, 1024, "%s/.lyrics", getenv("HOME")); mkdir(path, S_IRWXU); @@ -135,14 +139,11 @@ create_lyr_file(const char *artist, const char *title) static int store_lyr_hd(void) { - FILE *lyr_file; - unsigned i; - - lyr_file = create_lyr_file(current.artist, current.title); + FILE *lyr_file = create_lyr_file(current.artist, current.title); if (lyr_file == NULL) return -1; - for (i = 0; i < text.lines->len; ++i) + for (unsigned i = 0; i < text.lines->len; ++i) fprintf(lyr_file, "%s\n", (const char*)g_ptr_array_index(text.lines, i)); @@ -153,11 +154,10 @@ store_lyr_hd(void) static int delete_lyr_hd(void) { - char path[1024]; - if (!exists_lyr_file(current.artist, current.title)) return -1; + char path[1024]; path_lyr_file(path, 1024, current.artist, current.title); if (unlink(path) != 0) return -2; @@ -168,7 +168,19 @@ delete_lyr_hd(void) static void screen_lyrics_set(const GString *str) { - screen_text_set(&text, str); + if (reloading) { + unsigned saved_start = text.lw->start; + + screen_text_set(&text, str->str); + + /* restore the cursor and ensure that it's still valid */ + text.lw->start = saved_start; + list_window_fetch_cursor(text.lw); + } else { + screen_text_set(&text, str->str); + } + + reloading = false; /* paint new data */ @@ -177,7 +189,7 @@ screen_lyrics_set(const GString *str) static void screen_lyrics_callback(const GString *result, const bool success, - const char *plugin_name, G_GNUC_UNUSED void *data) + const char *plugin_name, gcc_unused void *data) { assert(current.loader != NULL); @@ -206,7 +218,7 @@ screen_lyrics_callback(const GString *result, const bool success, } static gboolean -screen_lyrics_timeout_callback(gpointer G_GNUC_UNUSED data) +screen_lyrics_timeout_callback(gpointer gcc_unused data) { plugin_stop(current.loader); current.loader = NULL; @@ -221,15 +233,13 @@ screen_lyrics_timeout_callback(gpointer G_GNUC_UNUSED data) static void screen_lyrics_load(const struct mpd_song *song) { - const char *artist, *title; - assert(song != NULL); screen_lyrics_abort(); screen_text_clear(&text); - artist = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0); - title = mpd_song_get_tag(song, MPD_TAG_TITLE, 0); + const char *artist = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0); + const char *title = mpd_song_get_tag(song, MPD_TAG_TITLE, 0); current.song = mpd_song_dup(song); current.artist = g_strdup(artist); @@ -251,6 +261,7 @@ screen_lyrics_reload(void) { if (current.loader == NULL && current.artist != NULL && current.title != NULL) { + reloading = true; current.loader = lyrics_load(current.artist, current.title, screen_lyrics_callback, NULL); screen_text_repaint(&text); @@ -258,13 +269,13 @@ screen_lyrics_reload(void) } static void -lyrics_screen_init(WINDOW *w, int cols, int rows) +lyrics_screen_init(WINDOW *w, unsigned cols, unsigned rows) { screen_text_init(&text, w, cols, rows); } static void -lyrics_resize(int cols, int rows) +lyrics_resize(unsigned cols, unsigned rows) { screen_text_resize(&text, cols, rows); } @@ -341,6 +352,70 @@ lyrics_paint(void) screen_text_paint(&text); } +/* save current lyrics to a file and run editor on it */ +static void +lyrics_edit(void) +{ + char *editor = options.text_editor; + if (editor == NULL) { + screen_status_message(_("Editor not configured")); + return; + } + + if (options.text_editor_ask) { + const char *prompt = + _("Do you really want to start an editor and edit these lyrics?"); + bool really = screen_get_yesno(prompt, false); + if (!really) { + screen_status_message(_("Aborted")); + return; + } + } + + if (store_lyr_hd() < 0) + return; + + ncu_deinit(); + + /* TODO: fork/exec/wait won't work on Windows, but building a command + string for system() is too tricky */ + int status; + pid_t pid = fork(); + if (pid == -1) { + screen_status_printf(("%s (%s)"), _("Can't start editor"), g_strerror(errno)); + ncu_init(); + return; + } else if (pid == 0) { + char path[1024]; + path_lyr_file(path, sizeof(path), current.artist, current.title); + execlp(editor, editor, path, NULL); + /* exec failed, do what system does */ + _exit(127); + } else { + int ret; + do { + ret = waitpid(pid, &status, 0); + } while (ret == -1 && errno == EINTR); + } + + ncu_init(); + + /* TODO: hardly portable */ + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) + /* update to get the changes */ + screen_lyrics_reload(); + else if (WEXITSTATUS(status) == 127) + screen_status_message(_("Can't start editor")); + else + screen_status_printf(_("Editor exited unexpectedly (%d)"), + WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + screen_status_printf(_("Editor exited unexpectedly (signal %d)"), + WTERMSIG(status)); + } +} + static bool lyrics_cmd(struct mpdclient *c, command_t cmd) { @@ -376,9 +451,12 @@ lyrics_cmd(struct mpdclient *c, command_t cmd) case CMD_LYRICS_UPDATE: if (c->song != NULL) { screen_lyrics_load(c->song); - screen_text_repaint(&text); + screen_text_paint(&text); } return true; + case CMD_EDIT: + lyrics_edit(); + return true; case CMD_SELECT: screen_lyrics_reload(); return true;