From ad58ebcc8a950f4624cfb1a836e18a703c3b6610 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Sun, 30 Sep 2007 14:27:08 +0100 Subject: [PATCH] disobedience control buttons reflect current state properly Organization: Straylight/Edgeware From: rjk@greenend.org.uk <> --- disobedience/control.c | 23 +++++++++++++++--- disobedience/disobedience.c | 2 ++ lib/eclient.c | 47 +++++++++++++++++++++++++++++++++---- lib/eclient.h | 2 ++ 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/disobedience/control.c b/disobedience/control.c index 5e2e0d3..f65c78c 100644 --- a/disobedience/control.c +++ b/disobedience/control.c @@ -155,7 +155,7 @@ GtkWidget *control_widget(void) { return hbox; } -/* Update the control bar after some kind of state change */ +/** @brief Update the control bar after some kind of state change */ void control_update(void) { int n; double l, r; @@ -171,10 +171,27 @@ void control_update(void) { --suppress_set_volume; } +/** @brief Update the state of one of the control icons + * @param button Widget for button + * @param visible True if this version of the button should be visible + * @param usable True if the button is currently usable + * + * Several of the icons, rather bizarrely, come in pairs: for instance exactly + * one of the play and pause buttons is supposed to be visible at any given + * moment. + * + * @p usable need not take into account server availability, that is done + * automatically. + */ static void update_icon(GtkWidget *button, - int visible, int attribute((unused)) usable) { + int visible, int usable) { + /* If the connection is down nothing is ever usable */ + if(!disorder_eclient_connected(client)) + usable = 0; (visible ? gtk_widget_show : gtk_widget_hide)(button); - /* TODO: show usability */ + /* Only both updating usability if the button is visible */ + if(visible) + gtk_widget_set_sensitive(button, usable); } static void update_pause(const struct icon *icon) { diff --git a/disobedience/disobedience.c b/disobedience/disobedience.c index 5f57f20..b45b007 100644 --- a/disobedience/disobedience.c +++ b/disobedience/disobedience.c @@ -461,6 +461,8 @@ int main(int argc, char **argv) { /* reset styles now everything has its name */ gtk_rc_reset_styles(gtk_settings_get_for_screen(gdk_screen_get_default())); gtk_widget_show_all(toplevel); + /* set initial control button visibility/usability */ + control_update(); D(("enter main loop")); MTAG("misc"); g_main_loop_run(mainloop); diff --git a/lib/eclient.c b/lib/eclient.c index 57680ca..43fafac 100644 --- a/lib/eclient.c +++ b/lib/eclient.c @@ -99,7 +99,13 @@ struct operation { void (*completed)(); /**< @brief user completion callback or 0 */ void *v; /**< @brief data for COMPLETED */ disorder_eclient *client; /**< @brief owning client */ - int sent; /**< @brief true if sent to server */ + + /** @brief true if sent to server + * + * This is cleared by disorder_eclient_close(), forcing all queued + * commands to be transparently resent. + */ + int sent; }; /** @brief Client structure */ @@ -217,7 +223,13 @@ disorder_eclient *disorder_eclient_new(const disorder_eclient_callbacks *cb, return c; } -/** @brief Disconnect a client */ +/** @brief Disconnect a client + * @param c Client to disconnect + * + * NB that this routine just disconnnects the TCP connection. It does not + * destroy the client! If you continue to use it then it will attempt to + * reconnect. + */ void disorder_eclient_close(disorder_eclient *c) { struct operation *op; @@ -238,9 +250,34 @@ void disorder_eclient_close(disorder_eclient *c) { op->sent = 0; } +/** @brief Return true if @c c is connected + * + * By connected it is meant that commands have a reasonable chance of being + * processed soon, not merely that a TCP connection exists - for instance if + * the client is still authenticating then that does not count as connected. + */ +int disorder_eclient_connected(const disorder_eclient *c) { + switch(c->state) { + case state_disconnected: + case state_connecting: + case state_connected: + return 0; + case state_idle: + case state_cmdresponse: + case state_body: + case state_log: + return 1; + } + assert(!"reached"); +} + /* Error reporting ***********************************************************/ -/** @brief called when a connection error occurs */ +/** @brief called when a connection error occurs + * + * After this called we will be disconnected (by disorder_eclient_close()), + * so there will be a reconnection before any commands can be sent. + */ static int comms_error(disorder_eclient *c, const char *fmt, ...) { va_list ap; char *s; @@ -281,7 +318,7 @@ static int protocol_error(disorder_eclient *c, struct operation *op, */ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { struct operation *op; - + D(("disorder_eclient_polled fd=%d state=%s mode=[%s %s]", c->fd, states[c->state], mode & DISORDER_POLL_READ ? "READ" : "", @@ -445,7 +482,7 @@ static int start_connect(void *cc, return 0; } -/** @brief Called when maybe connected */ +/** @brief Called when poll triggers while waiting for a connection */ static void maybe_connected(disorder_eclient *c) { /* We either connected, or got an error. */ int err; diff --git a/lib/eclient.h b/lib/eclient.h index dd8d9ba..d1e4e97 100644 --- a/lib/eclient.h +++ b/lib/eclient.h @@ -142,6 +142,8 @@ disorder_eclient *disorder_eclient_new(const disorder_eclient_callbacks *cb, void disorder_eclient_close(disorder_eclient *c); /* Close C */ +int disorder_eclient_connected(const disorder_eclient *c); + void disorder_eclient_polled(disorder_eclient *c, unsigned mode); /* Should be called when c's FD is readable and/or writable, and in any case * from time to time (so that retries work). */ -- [mdw]