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:
M | Makefile | | | 2 | +- |
M | history.c | | | 28 | ++++++++++++++++++++++++++-- |
M | history.h | | | 5 | ++++- |
D | link.c | | | 100 | ------------------------------------------------------------------------------- |
D | link.h | | | 30 | ------------------------------ |
A | list.c | | | 102 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | list.h | | | 33 | +++++++++++++++++++++++++++++++++ |
M | main.c | | | 240 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
M | player.c | | | 73 | ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
M | player.h | | | 6 | +++++- |
A | ref.c | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ref.h | | | 16 | ++++++++++++++++ |
M | tag.c | | | 49 | ------------------------------------------------- |
M | tag.h | | | 10 | ---------- |
M | track.c | | | 9 | +++------ |
M | track.h | | | 13 | ++----------- |
M | util.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);
}