tmus

TUI Music Player
git clone https://git.sinitax.com/sinitax/tmus
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

commit 3eea7a245a7ed49127a222628543f9509a6ff2b6
parent 15a8fe2cf2b16af8739a7ec2b64b5c5f184161b8
Author: Louis Burda <quent.burda@gmail.com>
Date:   Thu, 16 Dec 2021 17:11:12 +0100

Switched most buffers to wide chars, added general ref class, now clear mpd errors, added track and command completion

Diffstat:
MMakefile | 2+-
Mhistory.c | 28++++++++++++++++++++++++++--
Mhistory.h | 5++++-
Dlink.c | 100-------------------------------------------------------------------------------
Dlink.h | 30------------------------------
Alist.c | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alist.h | 33+++++++++++++++++++++++++++++++++
Mmain.c | 240+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mplayer.c | 73++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mplayer.h | 6+++++-
Aref.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aref.h | 16++++++++++++++++
Mtag.c | 49-------------------------------------------------
Mtag.h | 10----------
Mtrack.c | 9+++------
Mtrack.h | 13++-----------
Mutil.c | 3+++
17 files changed, 477 insertions(+), 310 deletions(-)

diff --git a/Makefile b/Makefile @@ -11,7 +11,7 @@ clean: %.o: %.c %.h $(CC) -c -o $@ $< $(CFLAGS) $(LDLIBS) -tmus: main.c util.o history.o link.o player.o tag.o track.o listnav.o +tmus: main.c util.o history.o list.o player.o tag.o track.o listnav.o ref.o $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) install: diff --git a/history.c b/history.c @@ -1,5 +1,4 @@ #include "history.h" -#include "link.h" #include "util.h" #include <string.h> @@ -45,7 +44,6 @@ history_free(struct history *history) free(ln); } history->list = LIST_HEAD; - free(history->query); history->query = NULL; history->cmd = NULL; } @@ -170,6 +168,8 @@ inputln_addch(struct inputln *line, wchar_t c) line->len++; line->cur++; + + line->buf[line->len] = '\0'; } void @@ -189,3 +189,27 @@ inputln_del(struct inputln *line, int n) line->len -= n; line->cur -= n; } + +void +inputln_copy(struct inputln *dst, struct inputln *src) +{ + if (dst->buf) { + free(dst->buf); + dst->buf = NULL; + } + dst->len = src->len; + dst->buf = wcsdup(src->buf); + ASSERT(dst->buf != NULL); + dst->cap = src->len + 1; + dst->cur = dst->len; +} + +void +inputln_replace(struct inputln *line, const wchar_t *str) +{ + line->buf = wcsdup(str); + ASSERT(line->buf != NULL); + line->len = wcslen(str); + line->cap = line->len + 1; + line->cur = line->len; +} diff --git a/history.h b/history.h @@ -1,6 +1,6 @@ #pragma once -#include "link.h" +#include "list.h" #include "wchar.h" @@ -38,3 +38,6 @@ void inputln_right(struct inputln *line); void inputln_addch(struct inputln *line, wchar_t c); void inputln_del(struct inputln *line, int n); + +void inputln_copy(struct inputln *dst, struct inputln *src); +void inputln_replace(struct inputln *line, const wchar_t *str); diff --git a/link.c b/link.c @@ -1,100 +0,0 @@ -#include "link.h" -#include "util.h" - -int -list_len(struct link *head) -{ - struct link *iter; - int len; - - ASSERT(head != NULL); - - len = 0; - for (iter = head->next; iter; iter = iter->next) - len += 1; - - return len; -} - -int -list_ffind(struct link *head, struct link *link) -{ - struct link *iter; - - ASSERT(head != NULL); - - for (iter = head->next; iter && iter != link; iter = iter->next); - - return (iter == link); -} - -struct link * -link_back(struct link *link) -{ - ASSERT(link != NULL); - - for (; link->next; link = link->next); - - return link; -} - -void -link_prepend(struct link *cur, struct link *link) -{ - ASSERT(cur != NULL && link != NULL); - - link->prev = cur->prev; - link->next = cur; - - if (link->prev) - link->prev->next = link; - if (link->next) - link->next->prev = link; -} - -void -link_append(struct link *cur, struct link *link) -{ - ASSERT(cur != NULL && link != NULL); - - link->prev = cur; - link->next = cur->next; - - if (link->prev) - link->prev->next = link; - if (link->next) - link->next->prev = link; -} - -void -link_pop(struct link *link) -{ - ASSERT(link != NULL); - - if (link->prev) - link->prev->next = link->next; - if (link->next) - link->next->prev = link->prev; -} - -struct link * -link_iter(struct link *link, int n) -{ - int i; - - for (i = 0; i < n; i++) { - if (!link) return NULL; - link = link->next; - } - - return link; -} - -void -link_push_back(struct link *cur, struct link *link) -{ - struct link *back; - - back = link_back(cur); - link_append(back, link); -} diff --git a/link.h b/link.h @@ -1,30 +0,0 @@ -#pragma once - -#include <stdlib.h> - -#define OFFSET(type, attr) ((size_t) &((type *)0)->attr) -#define UPCAST(ptr, type) ({ \ - const typeof( ((type *)0)->link ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - OFFSET(type, link) ); }) - -#define LIST_HEAD ((struct link) { .prev = NULL, .next = NULL }) -#define LINK_EMPTY ((struct link) { 0 }) - -struct link { - struct link *prev; - struct link *next; -}; - -/* list_XXX functions operate on the list head */ - -int list_len(struct link *head); -int list_ffind(struct link *head, struct link *link); - -struct link *link_back(struct link *list); -void link_prepend(struct link *list, struct link *link); -void link_append(struct link *list, struct link *link); -void link_pop(struct link *link); - -struct link *link_iter(struct link *link, int n); - -void link_push_back(struct link *list, struct link *link); diff --git a/list.c b/list.c @@ -0,0 +1,102 @@ +#include "list.h" +#include "util.h" + +int +list_len(struct link *head) +{ + struct link *iter; + int len; + + ASSERT(head != NULL); + + len = 0; + for (iter = head->next; iter; iter = iter->next) + len += 1; + + return len; +} + +int +list_ffind(struct link *head, struct link *link) +{ + struct link *iter; + + ASSERT(head != NULL); + + for (iter = head->next; iter && iter != link; iter = iter->next); + + return (iter == link); +} + +struct link * +link_back(struct link *link) +{ + ASSERT(link != NULL); + + for (; link->next; link = link->next); + + return link; +} + +void +link_prepend(struct link *cur, struct link *link) +{ + ASSERT(cur != NULL && link != NULL); + + link->prev = cur->prev; + link->next = cur; + + if (link->prev) + link->prev->next = link; + if (link->next) + link->next->prev = link; +} + +void +link_append(struct link *cur, struct link *link) +{ + ASSERT(cur != NULL && link != NULL); + + link->prev = cur; + link->next = cur->next; + + if (link->prev) + link->prev->next = link; + if (link->next) + link->next->prev = link; +} + +struct link * +link_pop(struct link *link) +{ + ASSERT(link != NULL); + + if (link->prev) + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + + return link; +} + +struct link * +link_iter(struct link *link, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (!link) return NULL; + link = link->next; + } + + return link; +} + +void +list_push_back(struct link *cur, struct link *link) +{ + struct link *back; + + back = link_back(cur); + link_append(back, link); +} diff --git a/list.h b/list.h @@ -0,0 +1,33 @@ +#pragma once + +#include <stdlib.h> + +#define OFFSET(type, attr) ((size_t) &((type *)0)->attr) +#define UPCAST(ptr, type) ({ \ + const typeof( ((type *)0)->link ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - OFFSET(type, link) ); }) + +#define LIST_HEAD ((struct link) { .prev = NULL, .next = NULL }) +#define LINK_EMPTY ((struct link) { 0 }) + +#define LINK(p) (&(p)->link) + +struct link { + struct link *prev; + struct link *next; +}; + +/* list_XXX functions operate on the list head */ + +int list_len(struct link *head); +int list_ffind(struct link *head, struct link *link); + +struct link *link_back(struct link *list); +void link_prepend(struct link *list, struct link *link); +void link_append(struct link *list, struct link *link); +struct link *link_pop(struct link *link); + +struct link *link_iter(struct link *link, int n); + +void list_push_back(struct link *list, struct link *link); + diff --git a/main.c b/main.c @@ -2,12 +2,13 @@ #define _DEFAULT_SOURCE #include "util.h" -#include "link.h" +#include "list.h" #include "history.h" #include "tag.h" #include "track.h" #include "player.h" #include "listnav.h" +#include "ref.h" #include "mpd/player.h" #include "curses.h" @@ -53,7 +54,7 @@ struct pane; typedef int (*pane_handler)(wint_t c); typedef void (*pane_updater)(struct pane *pane, int sel); -typedef char *(*completion_generator)(const char *text, int state); +typedef wchar_t *(*completion_generator)(const wchar_t *text, int state); typedef int (*cmd_handler)(const char *args); struct pane { @@ -67,7 +68,7 @@ struct pane { }; struct cmd { - const char *name; + const wchar_t *name; cmd_handler func; }; @@ -85,12 +86,21 @@ struct pane *const panes[] = { &pane_bot }; +struct inputln completion_query = { 0 }; +int completion_reset = 1; completion_generator completion; + struct pane *cmd_pane; struct history search_history, command_history; struct history *history; int cmd_show, cmd_mode; +const char player_state_chars[] = { + [PLAYER_STATE_PAUSED] = '|', + [PLAYER_STATE_PLAYING] = '>', + [PLAYER_STATE_STOPPED] = '#' +}; + struct pane *tag_pane; struct listnav tag_nav; struct link tags; @@ -121,8 +131,8 @@ void style_init(int style, int fg, int bg, int attr); void style_on(WINDOW *win, int style); void style_off(WINDOW *win, int style); -char *command_name_generator(const char *text, int state); -char *track_name_generator(const char *text, int state); +wchar_t *command_name_generator(const wchar_t *text, int state); +wchar_t *track_name_generator(const wchar_t *text, int state); int tag_input(wint_t c); void tag_vis(struct pane *pane, int sel); @@ -139,7 +149,7 @@ void main_vis(void); int usercmd_save(const char *args); const struct cmd cmds[] = { - { "save", usercmd_save }, + { L"save", usercmd_save }, }; void @@ -186,6 +196,7 @@ init(void) pane_sel = &pane_left; pane_top_sel = pane_sel; + playlist = LIST_HEAD; tags_sel = LIST_HEAD; listnav_init(&tag_nav); listnav_init(&track_nav); @@ -194,17 +205,17 @@ init(void) void cleanup(void) { + delwin(pane_left.win); + delwin(pane_right.win); + delwin(pane_bot.win); + endwin(); + data_save(); player_free(); history_free(&search_history); history_free(&command_history); - - delwin(pane_left.win); - delwin(pane_right.win); - delwin(pane_bot.win); - endwin(); } void @@ -235,7 +246,7 @@ data_load(void) tag->name = sanitized(tag->fname); ASSERT(tag->name != NULL); tag->link = LINK_EMPTY; - link_push_back(&tags, &tag->link); + list_push_back(&tags, LINK(tag)); tracks_load(tag); } @@ -247,7 +258,7 @@ tracks_load(struct tag *tag) { struct dirent *ent; struct track *track; - struct tag_ref *tagref; + struct ref *ref; DIR *dir; dir = opendir(tag->fpath); @@ -261,13 +272,9 @@ tracks_load(struct tag *tag) continue; track = track_init(tag->fpath, ent->d_name); - tagref = malloc(sizeof(struct tag_ref)); - ASSERT(tagref != NULL); - tagref->tag = tag; - tagref->link = LINK_EMPTY; - link_push_back(&track->tags, &tagref->link); - - link_push_back(&tracks, &track->link); + ref = ref_init(tag); + list_push_back(&track->tags, LINK(ref)); + list_push_back(&tracks, LINK(track)); } closedir(dir); } @@ -364,26 +371,28 @@ style_off(WINDOW *win, int style) ATTR_OFF(win, COLOR_PAIR(style) | style_attrs[style]); } -char * -command_name_generator(const char *text, int reset) +wchar_t * +command_name_generator(const wchar_t *text, int reset) { static int index, len; if (reset) { index = 0; - len = strlen(text); + len = wcslen(text); + } else { + index++; } for (; index < ARRLEN(cmds); index++) { - if (!strncmp(cmds[index].name, text, len)) - return strdup(cmds[index].name); + if (!wcsncmp(cmds[index].name, text, len)) + return wcsdup(cmds[index].name); } return NULL; } -char * -track_name_generator(const char *text, int reset) +wchar_t * +track_name_generator(const wchar_t *text, int reset) { static struct link *cur; struct track *track; @@ -391,13 +400,15 @@ track_name_generator(const char *text, int reset) if (reset) { cur = tracks.next; - len = strlen(text); + len = wcslen(text); + } else if (cur) { + cur = cur->next; } for (; cur; cur = cur->next) { track = UPCAST(cur, struct track); - if (!strncmp(track->name, text, len)) - return strdup(track->name); + if (!wcsncmp(track->name, text, len)) + return wcsdup(track->name); } return NULL; @@ -406,8 +417,10 @@ track_name_generator(const char *text, int reset) int tag_input(wint_t c) { - struct link *cur; + struct link *tag_link, *iter; + struct track *track; struct tag *tag; + struct ref *ref; switch (c) { case KEY_UP: @@ -417,13 +430,25 @@ tag_input(wint_t c) listnav_update_sel(&tag_nav, tag_nav.sel + 1); return 1; case KEY_SPACE: - cur = link_iter(tags.next, tag_nav.sel); - ASSERT(cur != NULL); - tag = UPCAST(cur, struct tag); - if (tagrefs_incl(&tags_sel, tag)) { - tagrefs_rm(&tags_sel, tag); + tag_link = link_iter(tags.next, tag_nav.sel); + ASSERT(tag_link != NULL); + tag = UPCAST(tag_link, struct tag); + if (refs_incl(&tags_sel, tag)) { + refs_rm(&tags_sel, tag); } else { - tagrefs_add(&tags_sel, tag); + ref = ref_init(tag); + list_push_back(&tags_sel, LINK(ref)); + } + refs_free(&playlist); + for (tag_link = tags_sel.next; tag_link; tag_link = tag_link->next) { + tag = UPCAST(tag_link, struct ref)->data; + for (iter = tracks.next; iter; iter = iter->next) { + track = UPCAST(iter, struct track); + if (refs_incl(&track->tags, tag) && !refs_incl(&playlist, track)) { + ref = ref_init(track); + list_push_back(&playlist, LINK(ref)); + } + } } return 1; case KEY_NPAGE: @@ -453,7 +478,7 @@ tag_vis(struct pane *pane, int sel) index = 0; for (iter = tags.next; iter; iter = iter->next) { tag = UPCAST(iter, struct tag); - tsel = tagrefs_incl(&tags_sel, tag); + tsel = refs_incl(&tags_sel, tag); if (sel && index == tag_nav.sel && tsel) style_on(pane->win, STYLE_ITEM_HOVER_SEL); @@ -495,10 +520,10 @@ track_input(wint_t c) player->track = track; player_play_track(track); return 1; - case KEY_NPAGE: + case KEY_PPAGE: listnav_update_sel(&track_nav, track_nav.sel - track_nav.wlen / 2); return 1; - case KEY_PPAGE: + case KEY_NPAGE: listnav_update_sel(&track_nav, track_nav.sel + track_nav.wlen / 2); return 1; } @@ -516,15 +541,15 @@ track_vis(struct pane *pane, int sel) werase(pane->win); pane_title(pane, "Tracks", sel); - listnav_update_bounds(&track_nav, 0, list_len(&tracks)); + listnav_update_bounds(&track_nav, 0, list_len(&playlist)); listnav_update_wlen(&track_nav, pane->h - 1); - wmove(pane->win, 0, 45); - wprintw(pane->win, "%i %i", list_len(&tracks), track_nav.sel); + wmove(pane->win, 0, 50); + wprintw(pane->win, "%i", list_len(&playlist)); index = 0; - for (iter = tracks.next; iter; iter = iter->next, index++) { - track = UPCAST(iter, struct track); + for (iter = playlist.next; iter; iter = iter->next, index++) { + track = UPCAST(iter, struct ref)->data; if (index < track_nav.wmin) continue; if (index >= track_nav.wmax) break; @@ -537,7 +562,7 @@ track_vis(struct pane *pane, int sel) style_on(pane->win, STYLE_ITEM_SEL); wmove(pane->win, 1 + index - track_nav.wmin, 0); - wprintw(pane->win, "%-*.*s", pane->w, pane->w, track->name); + wprintw(pane->win, "%-*.*ls", pane->w, pane->w, track->name); if (sel && index == track_nav.sel && track == player->track) style_off(pane->win, STYLE_ITEM_HOVER_SEL); @@ -551,10 +576,14 @@ track_vis(struct pane *pane, int sel) int cmd_input(wint_t c) { + struct track *track; + struct link *iter; + wchar_t *res; + if (cmd_mode == IMODE_EXECUTE) { history = &command_history; completion = command_name_generator; - } else { + } else if (cmd_mode == IMODE_SEARCH) { history = &search_history; completion = track_name_generator; } @@ -583,18 +612,51 @@ cmd_input(wint_t c) history_prev(history); break; case KEY_ENTER: - history_submit(history); - if (!*history->cmd->buf) + if (!*history->cmd->buf) { pane_sel = pane_top_sel; + break; + } + if (cmd_mode == IMODE_EXECUTE) { + + } else { + for (iter = tracks.next; iter; iter = iter->next) { + track = UPCAST(iter, struct track); + if (!wcscmp(track->name, history->cmd->buf)) { + player_play_track(track); + break; + } + } + } + history_submit(history); + pane_sel = pane_top_sel; break; case KEY_TAB: + if (history->cmd != history->query) { + inputln_copy(history->query, history->cmd); + history->cmd = history->query; + } + + if (completion_reset) + inputln_copy(&completion_query, history->query); + + res = completion(completion_query.buf, completion_reset); + if (res) inputln_replace(history->query, res); + free(res); + + completion_reset = 0; break; case KEY_BACKSPACE: + if (history->cmd->cur == 0) { + pane_sel = pane_top_sel; + break; + } inputln_del(history->cmd, 1); + completion_reset = 1; break; default: if (!iswprint(c)) return 0; inputln_addch(history->cmd, c); + completion_reset = 1; break; } return 1; @@ -604,28 +666,26 @@ void cmd_vis(struct pane *pane, int sel) { struct inputln *cmd; - char state_char; + struct link *iter; + int index, offset; char *line; werase(pane->win); wmove(pane->win, 0, 0); style_on(pane->win, STYLE_TITLE); - wprintw(pane->win, " %-*.*s\n", pane->w - 1, pane->w - 1, - player->track ? player->track->name : ""); + wprintw(pane->win, " %-*.*ls\n", pane->w - 1, pane->w - 1, + player->track ? player->track->name : L""); style_off(pane->win, STYLE_TITLE); - if (player->time_pos) { - state_char = player->state == PLAYER_STATE_PLAYING ? '>' : '|'; - line = appendstrf(NULL, "%c ", state_char); + if (player->loaded) { + line = appendstrf(NULL, "%c ", player_state_chars[player->state]); line = appendstrf(line, "%s / ", timestr(player->time_pos)); line = appendstrf(line, "%s", timestr(player->time_end)); - if (player->volume >= 0) { - line = appendstrf(line, " - vol: %u%", player->volume); - } - if (player->msg) { + if (player->volume >= 0) + line = appendstrf(line, " - vol: %u%%", player->volume); + if (player->msg) line = appendstrf(line, " | [PLAYER] %s", player->msg); - } wmove(pane->win, 1, 0); ATTR_ON(pane->win, A_REVERSE); @@ -633,16 +693,34 @@ cmd_vis(struct pane *pane, int sel) ATTR_OFF(pane->win, A_REVERSE); free(line); + } else { + if (player->msg) { + wmove(pane->win, 1, 0); + line = aprintf("[PLAYER] %s", player->msg); + wprintw(pane->win, "%-*.*s\n", pane->w, pane->w, line); + free(line); + } } if (sel || cmd_show) { - wmove(pane->win, 2, 0); - waddch(pane->win, cmd_mode == IMODE_SEARCH ? '/' : ':'); cmd = history->cmd; - wprintw(pane->win, "%-*.*ls", pane->w - 1, pane->w - 1, cmd->buf); + if (cmd != history->query) { + index = 0; + for (iter = history->list.next; iter; iter = iter->next, index++) + if (UPCAST(iter, struct inputln) == cmd) + break; + line = appendstrf(NULL, "[%i]%c ", iter ? index : -1, + cmd_mode == IMODE_SEARCH ? '/' : ':'); + } else { + line = appendstrf(NULL, "%c", cmd_mode == IMODE_SEARCH ? '/' : ':'); + } + offset = strlen(line); + line = appendstrf(line, "%ls", cmd->buf); + wprintw(pane->win, "%-*.*s", pane->w, pane->w, line); + free(line); if (sel) { /* cursor */ ATTR_ON(pane->win, A_REVERSE); - wmove(pane->win, 2, 1 + cmd->cur); + wmove(pane->win, 2, offset + cmd->cur); waddch(pane->win, cmd->cur < cmd->len ? cmd->buf[cmd->cur] : ' '); ATTR_OFF(pane->win, A_REVERSE); } @@ -675,35 +753,41 @@ main_input(wint_t c) player_next(); } break; - case 't': + case L't': + case L' ': player_toggle_pause(); break; - case 'n': - case '>': + case L'n': + case L'>': player_next(); break; - case 'p': - case '<': + case L'p': + case L'<': player_prev(); break; - case 'b': + case L'b': player_seek(0); break; - case ':': + case L's': + player_stop(); + break; + case L':': cmd_mode = IMODE_EXECUTE; pane_sel = &pane_bot; + completion_reset = 1; + break; + case L'/': + cmd_mode = IMODE_SEARCH; + pane_sel = &pane_bot; + completion_reset = 1; break; - case '+': + case L'+': player_set_volume(MIN(100, player->volume + 5)); break; - case '-': + case L'-': player_set_volume(MAX(0, player->volume - 5)); break; - case '/': - cmd_mode = IMODE_SEARCH; - pane_sel = &pane_bot; - break; - case 'q': + case L'q': quit = 1; break; } diff --git a/player.c b/player.c @@ -1,4 +1,5 @@ #include "player.h" +#include "ref.h" #include "portaudio.h" #include "sndfile.h" @@ -64,16 +65,30 @@ player_update(void) status = mpd_run_status(player->conn); ASSERT(status != NULL); - player->state = mpd_status_get_state(status) == MPD_STATE_PLAY - ? PLAYER_STATE_PLAYING : PLAYER_STATE_PAUSED; + switch (mpd_status_get_state(status)) { + case MPD_STATE_PAUSE: + player->state = PLAYER_STATE_PAUSED; + break; + case MPD_STATE_PLAY: + player->state = PLAYER_STATE_PLAYING; + break; + case MPD_STATE_STOP: + player->state = PLAYER_STATE_STOPPED; + break; + default: + ASSERT(0); + } player->volume = mpd_status_get_volume(status); song = mpd_run_current_song(player->conn); if (song) { + player->loaded = true; player->time_pos = mpd_status_get_elapsed_time(status); player->time_end = mpd_song_get_duration(song); mpd_song_free(song); } else { + player->track = NULL; + player->loaded = false; player->time_pos = 0; player->time_end = 0; } @@ -84,15 +99,12 @@ player_update(void) void player_queue_clear(void) { - struct link *iter, *next;; + struct ref *ref; - for (iter = &player->queue; iter; ) { - next = iter->next; - free(UPCAST(iter, struct track_ref)); - iter = next; + while (player->queue.next) { + ref = UPCAST(link_pop(player->queue.next), struct ref); + ref_free(ref); } - - player->queue = LIST_HEAD; } void @@ -104,19 +116,12 @@ player_queue_append(struct track *track) void player_queue_insert(struct track *track, size_t pos) { - struct track_ref *new; - struct link *iter; - int i; - - new = malloc(sizeof(struct track_ref)); - new->track = track; - new->link = LINK_EMPTY; + struct ref *ref; + struct link *link; - iter = &player->queue; - for (i = 0; i < pos && iter->next; i++) - iter = iter->next; - - link_append(iter, &new->link); + ref = ref_init(track); + link = link_iter(&player->queue, pos); + link_append(link, &ref->link); } int @@ -130,6 +135,7 @@ player_play_track(struct track *track) if (!mpd_run_add(player->conn, player->track->fpath) || !mpd_run_play(player->conn)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Playback failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } @@ -141,6 +147,7 @@ player_toggle_pause(void) { if (!mpd_run_toggle_pause(player->conn)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Pause toggle failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } @@ -152,6 +159,7 @@ player_pause(void) { if (!mpd_run_pause(player->conn, true)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Pausing track failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } @@ -163,6 +171,7 @@ player_resume(void) { if (!mpd_run_pause(player->conn, false)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Resuming track failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } @@ -174,6 +183,7 @@ player_next(void) { if (!mpd_run_next(player->conn)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Playing next track failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } @@ -185,6 +195,19 @@ player_prev(void) { if (!mpd_run_previous(player->conn)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Playing prev track failed"); + mpd_run_clearerror(player->conn); + return PLAYER_ERR; + } + + return PLAYER_OK; +} + +int +player_stop(void) +{ + if (!mpd_run_stop(player->conn)) { + PLAYER_STATUS(PLAYER_MSG_ERR, "Stopping track failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } @@ -194,8 +217,14 @@ player_prev(void) int player_seek(int sec) { + if (player->state == PLAYER_STATE_STOPPED) { + PLAYER_STATUS(PLAYER_MSG_ERR, "Cannot seek stopped track"); + return PLAYER_ERR; + } + if (!mpd_run_seek_current(player->conn, sec, false)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Track seek failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } @@ -207,11 +236,13 @@ player_set_volume(unsigned int vol) { if (player->volume == -1) { PLAYER_STATUS(PLAYER_MSG_INFO, "Setting volume not supported"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } if (!mpd_run_set_volume(player->conn, vol)) { PLAYER_STATUS(PLAYER_MSG_ERR, "Setting volume failed"); + mpd_run_clearerror(player->conn); return PLAYER_ERR; } diff --git a/player.h b/player.h @@ -1,6 +1,7 @@ #pragma once #include "track.h" +#include "list.h" #include "util.h" #include "mpd/client.h" @@ -20,7 +21,8 @@ enum { enum { PLAYER_STATE_PAUSED, - PLAYER_STATE_PLAYING + PLAYER_STATE_PLAYING, + PLAYER_STATE_STOPPED }; struct player { @@ -30,6 +32,7 @@ struct player { struct track *track; int state; + int loaded; int volume; unsigned int time_pos, time_end; @@ -53,6 +56,7 @@ int player_resume(void); int player_prev(void); int player_next(void); int player_seek(int sec); +int player_stop(void); int player_set_volume(unsigned int vol); diff --git a/ref.c b/ref.c @@ -0,0 +1,68 @@ +#include "ref.h" +#include "util.h" + +struct ref * +ref_init(void *data) +{ + struct ref *ref; + + ref = malloc(sizeof(struct ref)); + ASSERT(ref != NULL); + ref->link = LINK_EMPTY; + ref->data = data; + return ref; +} + +void +ref_free(struct ref *ref) +{ + free(ref); +} + +void +refs_free(struct link *head) +{ + struct link *cur; + + while (head->next) { + cur = link_pop(head->next); + ref_free(UPCAST(cur, struct ref)); + } +} + +static struct link * +refs_ffind(struct link *head, void *data) +{ + struct link *iter; + + for (iter = head->next; iter; iter = iter->next) { + if (UPCAST(iter, struct ref)->data == data) + return iter; + } + + return NULL; +} + +int +refs_incl(struct link *head, void *data) +{ + struct link *ref; + + ref = refs_ffind(head, data); + return ref != NULL; +} + +void +refs_rm(struct link *head, void *data) +{ + struct link *ref; + struct ref *dataref; + + ref = refs_ffind(head, data); + if (!ref) return; + + dataref = UPCAST(ref, struct ref); + link_pop(ref); + free(dataref); +} + diff --git a/ref.h b/ref.h @@ -0,0 +1,16 @@ +#pragma once + +#include "link.h" + +struct ref { + void *data; + + struct link link; +}; + +struct ref *ref_init(void *data); +void ref_free(struct ref *ref); + +void refs_free(struct link *head); +int refs_incl(struct link *head, void *data); +void refs_rm(struct link *head, void *data); diff --git a/tag.c b/tag.c @@ -1,53 +1,4 @@ #include "tag.h" #include "link.h" -static struct link * -tagrefs_ffind(struct link *head, struct tag *tag) -{ - struct link *iter; - for (iter = head->next; iter; iter = iter->next) { - if (UPCAST(iter, struct tag_ref)->tag == tag) - return iter; - } - - return NULL; -} - -int -tagrefs_incl(struct link *head, struct tag *tag) -{ - struct link *ref; - - ref = tagrefs_ffind(head, tag); - return ref != NULL; -} - -void -tagrefs_add(struct link *head, struct tag *tag) -{ - struct tag_ref *ref; - - if (tagrefs_incl(head, tag)) - return; - - ref = malloc(sizeof(struct tag_ref)); - ASSERT(ref != NULL); - ref->link = LINK_EMPTY; - ref->tag = tag; - link_push_back(head, &ref->link); -} - -void -tagrefs_rm(struct link *head, struct tag *tag) -{ - struct link *ref; - struct tag_ref *tagref; - - ref = tagrefs_ffind(head, tag); - if (!ref) return; - - tagref = UPCAST(ref, struct tag_ref); - link_pop(ref); - free(tagref); -} diff --git a/tag.h b/tag.h @@ -10,13 +10,3 @@ struct tag { struct link link; }; -struct tag_ref { - struct tag *tag; - - struct link link; -}; - -int tagrefs_incl(struct link *head, struct tag *tag); -void tagrefs_add(struct link *head, struct tag *tag); -void tagrefs_rm(struct link *head, struct tag *tag); - diff --git a/track.c b/track.c @@ -1,5 +1,6 @@ #include "track.h" +#include <wchar.h> #include <string.h> @@ -15,14 +16,10 @@ track_init(const char *dir, const char *file) ASSERT(track->fname != NULL); track->fpath = aprintf("%s/%s", dir, file); ASSERT(track->fpath != NULL); - track->name = sanitized(track->fname); - ASSERT(track->name != NULL); + track->name = calloc(strlen(track->fname) + 1, sizeof(wchar_t)); + mbstowcs(track->name, track->fname, strlen(track->fname) + 1); - // TODO track_load_info(track) - track->artist = NULL; - track->duration = 0; track->link = LINK_EMPTY; - track->tags = LIST_HEAD; return track; diff --git a/track.h b/track.h @@ -1,25 +1,16 @@ #pragma once -#include "link.h" +#include "list.h" #include "util.h" struct track { - char *name; - char *artist; - float duration; + wchar_t *name; struct link tags; char *fname, *fpath; struct link link; }; -struct track_ref { - struct track *track; - - struct link link; -}; - - struct track *track_init(const char *dir, const char *file); void track_free(struct track *t); diff --git a/util.c b/util.c @@ -2,6 +2,8 @@ #include "util.h" +#include "ncurses.h" + #include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -42,6 +44,7 @@ assert(int cond, const char *file, int line, const char *condstr) { if (cond) return; + endwin(); fprintf(stderr, "Assertion failed %s:%i (%s)\n", file, line, condstr); exit(1); }