chiark / gitweb /
disobedience control buttons reflect current state properly
authorrjk@greenend.org.uk <>
Sun, 30 Sep 2007 13:27:08 +0000 (14:27 +0100)
committerrjk@greenend.org.uk <>
Sun, 30 Sep 2007 13:27:08 +0000 (14:27 +0100)
disobedience/control.c
disobedience/disobedience.c
lib/eclient.c
lib/eclient.h

index 5e2e0d32c8828992b3846b9b13c9706805be321a..f65c78ca10bad6b1f2f51214ba4938feab0373ff 100644 (file)
@@ -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) {
index 5f57f2043e781aa96dfec068e0f4e0eb204efbd5..b45b0071277251ff17989c99620c722e3a596862 100644 (file)
@@ -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);
index 57680ca21f4350cca044347baeb17495dc6de833..43fafac7a219c1c40ef57f7d374b3e7a18d7c30d 100644 (file)
@@ -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;
index dd8d9bad0f4b5bb204cd1f9d10477e2d293661d5..d1e4e97d5ebd81fbf2868af85fcb9f5953085f77 100644 (file)
@@ -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). */