mpd: Implement idle events for Playing state
This commit is contained in:
@@ -82,6 +82,7 @@ class Idle : public State {
|
|||||||
class Playing : public State {
|
class Playing : public State {
|
||||||
Context* const ctx_;
|
Context* const ctx_;
|
||||||
sigc::connection timer_connection_;
|
sigc::connection timer_connection_;
|
||||||
|
sigc::connection idle_connection_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Playing(Context* const ctx) : ctx_{ctx} {}
|
Playing(Context* const ctx) : ctx_{ctx} {}
|
||||||
@@ -98,7 +99,10 @@ class Playing : public State {
|
|||||||
Playing(Playing const&) = delete;
|
Playing(Playing const&) = delete;
|
||||||
Playing& operator=(Playing const&) = delete;
|
Playing& operator=(Playing const&) = delete;
|
||||||
|
|
||||||
|
void timer() noexcept;
|
||||||
|
void idle() noexcept;
|
||||||
bool on_timer();
|
bool on_timer();
|
||||||
|
bool on_io(Glib::IOCondition const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Paused : public State {
|
class Paused : public State {
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ auto format_as(enum mpd_idle val) {
|
|||||||
|
|
||||||
namespace waybar::modules::detail {
|
namespace waybar::modules::detail {
|
||||||
|
|
||||||
#define IDLE_RUN_NOIDLE_AND_CMD(...) \
|
#define RUN_NOIDLE_AND_CMD(STATE, ...) \
|
||||||
if (idle_connection_.connected()) { \
|
if (idle_connection_.connected()) { \
|
||||||
idle_connection_.disconnect(); \
|
idle_connection_.disconnect(); \
|
||||||
auto conn = ctx_->connection().get(); \
|
auto conn = ctx_->connection().get(); \
|
||||||
if (!mpd_run_noidle(conn)) { \
|
if (!mpd_run_noidle(conn)) { \
|
||||||
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) { \
|
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) { \
|
||||||
spdlog::error("mpd: Idle: failed to unregister for IDLE events"); \
|
spdlog::error("mpd: STATE: failed to unregister for IDLE events"); \
|
||||||
ctx_->checkErrors(conn); \
|
ctx_->checkErrors(conn); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@@ -33,24 +33,23 @@ namespace waybar::modules::detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Idle::play() {
|
void Idle::play() {
|
||||||
IDLE_RUN_NOIDLE_AND_CMD(mpd_run_play(conn));
|
RUN_NOIDLE_AND_CMD(Idle, mpd_run_play(conn));
|
||||||
|
|
||||||
ctx_->setState(std::make_unique<Playing>(ctx_));
|
ctx_->setState(std::make_unique<Playing>(ctx_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Idle::pause() {
|
void Idle::pause() {
|
||||||
IDLE_RUN_NOIDLE_AND_CMD(mpd_run_pause(conn, true));
|
RUN_NOIDLE_AND_CMD(Idle, mpd_run_pause(conn, true));
|
||||||
|
|
||||||
ctx_->setState(std::make_unique<Paused>(ctx_));
|
ctx_->setState(std::make_unique<Paused>(ctx_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Idle::stop() {
|
void Idle::stop() {
|
||||||
IDLE_RUN_NOIDLE_AND_CMD(mpd_run_stop(conn));
|
RUN_NOIDLE_AND_CMD(Idle, mpd_run_stop(conn));
|
||||||
|
|
||||||
ctx_->setState(std::make_unique<Stopped>(ctx_));
|
ctx_->setState(std::make_unique<Stopped>(ctx_));
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef IDLE_RUN_NOIDLE_AND_CMD
|
|
||||||
|
|
||||||
void Idle::update() noexcept {
|
void Idle::update() noexcept {
|
||||||
// This is intentionally blank.
|
// This is intentionally blank.
|
||||||
@@ -118,18 +117,50 @@ bool Idle::on_io(Glib::IOCondition const&) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Playing::entry() noexcept {
|
void Playing::entry() noexcept {
|
||||||
sigc::slot<bool> timer_slot = sigc::mem_fun(*this, &Playing::on_timer);
|
timer();
|
||||||
timer_connection_ = Glib::signal_timeout().connect_seconds(timer_slot, 1);
|
idle();
|
||||||
spdlog::debug("mpd: Playing: enabled 1 second periodic timer.");
|
spdlog::debug("mpd: Playing: enabled 1 second periodic timer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playing::exit() noexcept {
|
void Playing::exit() noexcept {
|
||||||
|
if (idle_connection_.connected()) {
|
||||||
|
idle_connection_.disconnect();
|
||||||
|
spdlog::debug("mpd: Playing: unwatching FD");
|
||||||
|
}
|
||||||
|
|
||||||
if (timer_connection_.connected()) {
|
if (timer_connection_.connected()) {
|
||||||
timer_connection_.disconnect();
|
timer_connection_.disconnect();
|
||||||
spdlog::debug("mpd: Playing: disabled 1 second periodic timer.");
|
spdlog::debug("mpd: Playing: disabled 1 second periodic timer.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Playing::timer() noexcept {
|
||||||
|
if (timer_connection_.connected()) {
|
||||||
|
timer_connection_.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
sigc::slot<bool> timer_slot = sigc::mem_fun(*this, &Playing::on_timer);
|
||||||
|
timer_connection_ = Glib::signal_timeout().connect_seconds(timer_slot, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Playing::idle() noexcept {
|
||||||
|
auto conn = ctx_->connection().get();
|
||||||
|
assert(conn != nullptr);
|
||||||
|
|
||||||
|
if (!mpd_send_idle_mask(
|
||||||
|
conn, static_cast<mpd_idle>(MPD_IDLE_PLAYER | MPD_IDLE_OPTIONS | MPD_IDLE_QUEUE))) {
|
||||||
|
ctx_->checkErrors(conn);
|
||||||
|
spdlog::error("mpd: Playing: failed to register for IDLE events");
|
||||||
|
} else if (!idle_connection_.connected()) {
|
||||||
|
spdlog::trace("mpd: Playing: watching FD");
|
||||||
|
sigc::slot<bool, Glib::IOCondition const&> idle_slot = sigc::mem_fun(*this, &Playing::on_io);
|
||||||
|
idle_connection_ =
|
||||||
|
Glib::signal_io().connect(idle_slot, mpd_connection_get_fd(conn),
|
||||||
|
Glib::IO_IN | Glib::IO_PRI | Glib::IO_ERR | Glib::IO_HUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Playing::on_timer() {
|
bool Playing::on_timer() {
|
||||||
// Attempt to connect with MPD.
|
// Attempt to connect with MPD.
|
||||||
try {
|
try {
|
||||||
@@ -141,6 +172,8 @@ bool Playing::on_timer() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RUN_NOIDLE_AND_CMD(Playing);
|
||||||
|
|
||||||
ctx_->fetchState();
|
ctx_->fetchState();
|
||||||
|
|
||||||
if (!ctx_->is_playing()) {
|
if (!ctx_->is_playing()) {
|
||||||
@@ -154,6 +187,50 @@ bool Playing::on_timer() {
|
|||||||
|
|
||||||
ctx_->queryMPD();
|
ctx_->queryMPD();
|
||||||
ctx_->emit();
|
ctx_->emit();
|
||||||
|
|
||||||
|
idle();
|
||||||
|
} catch (std::exception const& e) {
|
||||||
|
spdlog::warn("mpd: Playing: error: {}", e.what());
|
||||||
|
ctx_->setState(std::make_unique<Disconnected>(ctx_));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Playing::on_io(Glib::IOCondition const&) {
|
||||||
|
auto conn = ctx_->connection().get();
|
||||||
|
|
||||||
|
// callback should do this:
|
||||||
|
enum mpd_idle events = mpd_recv_idle(conn, /* ignore_timeout?= */ false);
|
||||||
|
spdlog::debug("mpd: Playing: recv_idle events -> {}", events);
|
||||||
|
|
||||||
|
mpd_response_finish(conn);
|
||||||
|
try {
|
||||||
|
ctx_->checkErrors(conn);
|
||||||
|
|
||||||
|
ctx_->fetchState();
|
||||||
|
|
||||||
|
if (!ctx_->is_playing()) {
|
||||||
|
if (ctx_->is_paused()) {
|
||||||
|
ctx_->setState(std::make_unique<Paused>(ctx_));
|
||||||
|
} else {
|
||||||
|
ctx_->setState(std::make_unique<Stopped>(ctx_));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_->queryMPD();
|
||||||
|
ctx_->emit();
|
||||||
|
|
||||||
|
if (!mpd_send_idle_mask(
|
||||||
|
conn, static_cast<mpd_idle>(MPD_IDLE_PLAYER | MPD_IDLE_OPTIONS | MPD_IDLE_QUEUE))) {
|
||||||
|
ctx_->checkErrors(conn);
|
||||||
|
spdlog::error("mpd: Playing: failed to register for IDLE events");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer the next timer
|
||||||
|
timer();
|
||||||
} catch (std::exception const& e) {
|
} catch (std::exception const& e) {
|
||||||
spdlog::warn("mpd: Playing: error: {}", e.what());
|
spdlog::warn("mpd: Playing: error: {}", e.what());
|
||||||
ctx_->setState(std::make_unique<Disconnected>(ctx_));
|
ctx_->setState(std::make_unique<Disconnected>(ctx_));
|
||||||
@@ -164,21 +241,25 @@ bool Playing::on_timer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Playing::stop() {
|
void Playing::stop() {
|
||||||
|
RUN_NOIDLE_AND_CMD(Playing,
|
||||||
if (timer_connection_.connected()) {
|
if (timer_connection_.connected()) {
|
||||||
timer_connection_.disconnect();
|
timer_connection_.disconnect();
|
||||||
|
|
||||||
mpd_run_stop(ctx_->connection().get());
|
mpd_run_stop(ctx_->connection().get());
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
ctx_->setState(std::make_unique<Stopped>(ctx_));
|
ctx_->setState(std::make_unique<Stopped>(ctx_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playing::pause() {
|
void Playing::pause() {
|
||||||
|
RUN_NOIDLE_AND_CMD(Playing,
|
||||||
if (timer_connection_.connected()) {
|
if (timer_connection_.connected()) {
|
||||||
timer_connection_.disconnect();
|
timer_connection_.disconnect();
|
||||||
|
|
||||||
mpd_run_pause(ctx_->connection().get(), true);
|
mpd_run_pause(ctx_->connection().get(), true);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
ctx_->setState(std::make_unique<Paused>(ctx_));
|
ctx_->setState(std::make_unique<Paused>(ctx_));
|
||||||
}
|
}
|
||||||
@@ -387,4 +468,5 @@ bool Disconnected::on_timer() {
|
|||||||
|
|
||||||
void Disconnected::update() noexcept { ctx_->do_update(); }
|
void Disconnected::update() noexcept { ctx_->do_update(); }
|
||||||
|
|
||||||
|
#undef RUN_NOIDLE_AND_CMD
|
||||||
} // namespace waybar::modules::detail
|
} // namespace waybar::modules::detail
|
||||||
|
|||||||
Reference in New Issue
Block a user