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;
--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) {
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 */
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;
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;
*/
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" : "",
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;