chiark / gitweb /
Merge latest Disobedience changes
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 29 Jun 2008 12:30:10 +0000 (13:30 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 29 Jun 2008 12:30:10 +0000 (13:30 +0100)
CHANGES.html
disobedience/client.c
disobedience/disobedience.c
disobedience/disobedience.h
disobedience/login.c
disobedience/properties.c
disobedience/users.c
images/Makefile.am
images/logo256.png [new file with mode: 0644]
lib/eclient.c
lib/eclient.h

index 2a3c89421eed3974c11327b5b441ce4bec509181..31f55ad1a97b22c0870cf2a76a6f3cc6e67b977c 100644 (file)
@@ -57,6 +57,15 @@ span.command {
 
 <p>This file documents recent user-visible changes to DisOrder.</p>
 
+<h2>Changes up to version 4.1.1</h2>
+
+<div class=section>
+
+  <p>Disobedience's &ldquo;Login&rdquo; window now works when you are logged
+  in.</p>
+  
+</div>
+
 <h2>Changes up to version 4.1</h2>
 
 <div class=section>
index d81aac2f34c90287204c27a71b13a4c8e859139c..24069034a548f4a98622ad9571137231e7b38990 100644 (file)
@@ -68,8 +68,7 @@ static gboolean gtkclient_dispatch(GSource *source,
   if(revents & (G_IO_OUT|G_IO_HUP|G_IO_ERR))
     mode |= DISORDER_POLL_WRITE;
   time(&esource->last_poll);
-  if(!login_window)
-    disorder_eclient_polled(esource->client, mode);
+  disorder_eclient_polled(esource->client, mode);
   return TRUE;                          /* ??? not documented */
 }
 
@@ -126,19 +125,15 @@ static void gtkclient_comms_error(void attribute((unused)) *u,
 /** @brief Report a protocol-level error
  *
  * The error will not be retried.  We offer a callback to the submitter of the
- * original command and if none is supplied we pop up an error box.
+ * original command and if none is supplied we drop the error message in the
+ * status bar.
  */
 static void gtkclient_protocol_error(void attribute((unused)) *u,
-                                    void *v,
+                                    void attribute((unused)) *v,
                                      int code,
                                     const char *msg) {
-  struct callbackdata *cbd = v;
-
   D(("gtkclient_protocol_error %s", msg));
-  if(cbd && cbd->onerror)
-    cbd->onerror(cbd, code, msg);
-  else
-    popup_protocol_error(code, msg);
+  gtk_label_set_text(GTK_LABEL(report_label), msg);
 }
 
 /** @brief Report callback from eclient */
index ce6eb0354ce36cb311538a62dc59de35ce5a1b15..ce94e960256258e6537f9185baa703777e30be8d 100644 (file)
@@ -422,6 +422,8 @@ void logged_in(void) {
   periodic_fast(0);
   /* Recheck server version */
   disorder_eclient_version(client, version_completed, 0);
+  disorder_eclient_enable_connect(client);
+  disorder_eclient_enable_connect(logclient);
 }
 
 int main(int argc, char **argv) {
index 1f631088e4503a8969bf90c8ccb659255b62adf5..91d07de7fa671fd4f0e695bc11da2cb7954a6e9f 100644 (file)
@@ -53,6 +53,7 @@
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdkkeysyms.h>
 
 /* Types ------------------------------------------------------------------- */
 
@@ -60,28 +61,6 @@ struct queuelike;
 struct choosenode;
 struct progress_window;
 
-/** @brief Callback data structure
- *
- * This program is extremely heavily callback-driven.  Rather than have
- * numerous different callback structures we have a single one which can be
- * interpreted adequately both by success and error handlers.
- */
-struct callbackdata {
-  void (*onerror)(struct callbackdata *cbd,
-                  int code,
-                 const char *msg);     /* called on error */
-  union {
-    const char *key;                    /* gtkqueue.c op_part_lookup */
-    struct choosenode *choosenode;      /* gtkchoose.c got_files/got_dirs */
-    struct queuelike *ql;               /* gtkqueue.c queuelike_completed */
-    struct prefdata *f;                 /* properties.c */
-    const char *user;                   /* users.c */
-    struct {
-      const char *user, *email;         /* users.c */
-    } edituser;
-  } u;
-};
-
 /** @brief Per-tab callbacks
  *
  * Some of the options in the main menu depend on which tab is displayed, so we
index b1047d689fd2ea15b5b50a91f8b277349bb6610b..7cb64c9d38cc9efce7260356a9ac9f82476a8467 100644 (file)
@@ -29,7 +29,6 @@
  * It you hit Cancel then the window disappears without saving anything.
  *
  * TODO
- * - escape and return should work
  * - cancel/close should be consistent with properties
  */
 
@@ -163,6 +162,8 @@ static void login_ok(GtkButton attribute((unused)) *button,
   } else {
     /* Failed to connect - report the error */
     popup_msg(GTK_MESSAGE_ERROR, disorder_last(c));
+    /* TODO it would be nice to restore the config (not the entry contents!) to
+     * the last known good one if we were already connected to something. */
   }
   disorder_close(c);                    /* no use for this any more */
 }
@@ -173,6 +174,24 @@ static void login_cancel(GtkButton attribute((unused)) *button,
   gtk_widget_destroy(login_window);
 }
 
+/** @brief Keypress handler */
+static gboolean login_keypress(GtkWidget attribute((unused)) *widget,
+                               GdkEventKey *event,
+                               gpointer attribute((unused)) user_data) {
+  if(event->state)
+    return FALSE;
+  switch(event->keyval) {
+  case GDK_Return:
+    login_ok(0, 0);
+    return TRUE;
+  case GDK_Escape:
+    login_cancel(0, 0);
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
 /* Buttons that appear at the bottom of the window */
 static struct button buttons[] = {
   {
@@ -209,7 +228,7 @@ void login_box(void) {
                   G_CALLBACK(gtk_widget_destroyed), &login_window);
   gtk_window_set_title(GTK_WINDOW(login_window), "Login Details");
   /* Construct the form */
-  table = gtk_table_new(NLWIS + 1/*rows*/, 2/*columns*/, FALSE/*homogenous*/);
+  table = gtk_table_new(NLWIS/*rows*/, 2/*columns*/, FALSE/*homogenous*/);
   gtk_widget_set_style(table, tool_style);
   for(n = 0; n < NLWIS; ++n) {
     label = gtk_label_new(lwis[n].description);
@@ -234,6 +253,11 @@ void login_box(void) {
   }
   buttonbox = create_buttons(buttons, NBUTTONS);
   vbox = gtk_vbox_new(FALSE, 1);
+  gtk_box_pack_start(GTK_BOX(vbox),
+                     gtk_image_new_from_pixbuf(find_image("logo256.png")),
+                     TRUE/*expand*/,
+                     TRUE/*fill*/,
+                     4/*padding*/);
   gtk_box_pack_start(GTK_BOX(vbox), table, 
                      TRUE/*expand*/, TRUE/*fill*/, 1/*padding*/);
   gtk_box_pack_start(GTK_BOX(vbox), buttonbox,
@@ -241,6 +265,9 @@ void login_box(void) {
   gtk_container_add(GTK_CONTAINER(login_window), frame_widget(vbox, NULL));
   gtk_window_set_transient_for(GTK_WINDOW(login_window),
                                GTK_WINDOW(toplevel));
+  /* Keyboard shortcuts */
+  g_signal_connect(login_window, "key-press-event",
+                   G_CALLBACK(login_keypress), 0);
   gtk_widget_show_all(login_window);
 }
 
index 16ee97cbaaf59d352ac599757666f273bbc50dcd..7c1c816aaaa70580950995cade0f8f976d98f4d4 100644 (file)
@@ -19,9 +19,6 @@
  */
 /** @file disobedience/properties.c
  * @brief Track properties editor
- *
- * TODO:
- * - return and escape keys should work 
  */
 #include "disobedience.h"
 
@@ -47,12 +44,6 @@ static void set_edited_boolean(struct prefdata *f, const char *value);
 static void set_boolean(struct prefdata *f, const char *value);
 
 static void prefdata_completed(void *v, const char *err, const char *value);
-static void prefdata_onerror(struct callbackdata *cbd,
-                             int code,
-                             const char *msg);
-static struct callbackdata *make_callbackdata(struct prefdata *f);
-static void prefdata_completed_common(struct prefdata *f,
-                                      const char *value);
 
 static void properties_ok(GtkButton *button, gpointer userdata);
 static void properties_apply(GtkButton *button, gpointer userdata);
@@ -179,6 +170,24 @@ static void propagate_clicked(GtkButton attribute((unused)) *button,
   }
 }
 
+/** @brief Keypress handler */
+static gboolean properties_keypress(GtkWidget attribute((unused)) *widget,
+                                    GdkEventKey *event,
+                                    gpointer attribute((unused)) user_data) {
+  if(event->state)
+    return FALSE;
+  switch(event->keyval) {
+  case GDK_Return:
+    properties_ok(0, 0);
+    return TRUE;
+  case GDK_Escape:
+    properties_cancel(0, 0);
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
 void properties(int ntracks, const char **tracks) {
   int n, m;
   struct prefdata *f;
@@ -205,6 +214,9 @@ void properties(int ntracks, const char **tracks) {
   gtk_widget_set_style(properties_window, tool_style);
   g_signal_connect(properties_window, "destroy",
                   G_CALLBACK(gtk_widget_destroyed), &properties_window);
+  /* Keyboard shortcuts */
+  g_signal_connect(properties_window, "key-press-event",
+                   G_CALLBACK(properties_keypress), 0);
   /* Most of the action is the table of preferences */
   properties_table = gtk_table_new((NPREFS + 1) * ntracks, 2 + ntracks > 1,
                                    FALSE);
@@ -311,8 +323,8 @@ static void kickoff_namepart(struct prefdata *f) {
    * wanted was the underlying preference, but in fact it should always match
    * and will supply a sane default without having to know how to parse tracks
    * names (which implies knowing collection roots). */
-  disorder_eclient_namepart(client, prefdata_completed, f->track, "display", f->p->part,
-                            make_callbackdata(f));
+  disorder_eclient_namepart(client, prefdata_completed,
+                            f->track, "display", f->p->part, f);
 }
 
 static void completed_namepart(struct prefdata *f) {
@@ -357,8 +369,7 @@ static void set_namepart_completed(void *v, const char *err) {
 /* String preferences ------------------------------------------------------ */
 
 static void kickoff_string(struct prefdata *f) {
-  disorder_eclient_get(client, prefdata_completed, f->track, f->p->part, 
-                      make_callbackdata(f));
+  disorder_eclient_get(client, prefdata_completed, f->track, f->p->part, f);
 }
 
 static void completed_string(struct prefdata *f) {
@@ -390,8 +401,7 @@ static void set_string(struct prefdata *f, const char *value) {
 /* Boolean preferences ----------------------------------------------------- */
 
 static void kickoff_boolean(struct prefdata *f) {
-  disorder_eclient_get(client, prefdata_completed, f->track, f->p->part, 
-                      make_callbackdata(f));
+  disorder_eclient_get(client, prefdata_completed, f->track, f->p->part, f);
 }
 
 static void completed_boolean(struct prefdata *f) {
@@ -424,34 +434,11 @@ static void set_boolean(struct prefdata *f, const char *value) {
 
 /* Querying preferences ---------------------------------------------------- */
 
-/* Make a suitable callbackdata */
-static struct callbackdata *make_callbackdata(struct prefdata *f) {
-  struct callbackdata *cbd = xmalloc(sizeof *cbd);
-
-  cbd->onerror = prefdata_onerror;
-  cbd->u.f = f;
-  return cbd;
-}
-
-/* No pref was set */
-static void prefdata_onerror(struct callbackdata *cbd,
-                             int attribute((unused)) code,
-                             const char attribute((unused)) *msg) {
-  prefdata_completed_common(cbd->u.f, 0);
-}
-
-/* Got the value of a pref */
 static void prefdata_completed(void *v, const char *err, const char *value) {
-  if(err) {
-  } else {
-    struct callbackdata *cbd = v;
-    
-    prefdata_completed_common(cbd->u.f, value);
-  }
-}
+  struct prefdata *const f = v;
 
-static void prefdata_completed_common(struct prefdata *f,
-                                      const char *value) {
+  if(err)
+    popup_protocol_error(0, err);
   f->value = value;
   f->p->type->completed(f);
   f->p->type->set_edited(f, f->value);
index a835ced63f0d26115f958685796dbcc8b0cadb6a..363684f14163f7b2418e42cd68aa4303ae721b35 100644 (file)
@@ -35,7 +35,6 @@
  *
  * TODO:
  * - enter new username in the GtkTreeView
- * - escape and enter keys should work
  * - should have a cancel or close button, consistent with properties and login
  */
 
@@ -672,6 +671,21 @@ static struct button users_buttons[] = {
 };
 #define NUSERS_BUTTONS (sizeof users_buttons / sizeof *users_buttons)
 
+/** @brief Keypress handler */
+static gboolean users_keypress(GtkWidget attribute((unused)) *widget,
+                               GdkEventKey *event,
+                               gpointer attribute((unused)) user_data) {
+  if(event->state)
+    return FALSE;
+  switch(event->keyval) {
+  case GDK_Escape:
+    gtk_widget_destroy(users_window);
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
 /** @brief Pop up the user management window */
 void manage_users(void) {
   GtkWidget *tree, *buttons, *hbox, *hbox2, *vbox, *vbox2;
@@ -692,6 +706,9 @@ void manage_users(void) {
   g_signal_connect(users_window, "destroy",
                   G_CALLBACK(gtk_widget_destroyed), &users_window);
   gtk_window_set_title(GTK_WINDOW(users_window), "User Management");
+  /* Keyboard shortcuts */
+  g_signal_connect(users_window, "key-press-event",
+                   G_CALLBACK(users_keypress), 0);
   /* default size is too small */
   gtk_window_set_default_size(GTK_WINDOW(users_window), 240, 240);
 
index 88145b1a083a5a020b8bb055bc7f62aa62ae5654..607d0254a465b1e17726c269db2394e6f6de58fd 100644 (file)
@@ -22,7 +22,7 @@ pkghttp_DATA=cross.png down.png downdown.png edit.png nocross.png     \
 nodown.png nodowndown.png noup.png noupup.png tick.png up.png upup.png \
 notes.png play.png pause.png random.png randomcross.png notescross.png \
 propagate.png speaker.png speakercross.png directory.png logo.png      \
-logosmall.png
+logosmall.png logo256.png
 
 EXTRA_DIST=$(pkghttp_DATA) duck.png disobedience16x16.xpm disobedience32x32.xpm
 
diff --git a/images/logo256.png b/images/logo256.png
new file mode 100644 (file)
index 0000000..e4e8006
Binary files /dev/null and b/images/logo256.png differ
index 48ae7e270d31c608922ac3e16a6a22672661a8d6..e7353df436e89540f113ff763da0ce4b93adf144 100644 (file)
@@ -144,6 +144,9 @@ struct disorder_eclient {
 
   /** @brief Protocol version */
   int protocol;
+
+  /** @brief True if enabled */
+  int enabled;
 };
 
 /* Forward declarations ******************************************************/
@@ -234,6 +237,7 @@ disorder_eclient *disorder_eclient_new(const disorder_eclient_callbacks *cb,
   c->callbacks = cb;
   c->u = u;
   c->opstail = &c->ops;
+  c->enabled = 1;
   vector_init(&c->vec);
   dynstr_init(&c->input);
   dynstr_init(&c->output);
@@ -271,6 +275,16 @@ void disorder_eclient_close(disorder_eclient *c) {
     c->log_callbacks->state(c->log_v, c->statebits);
 }
 
+/** @brief Permit new connection activity */
+void disorder_eclient_enable_connect(disorder_eclient *c) {
+  c->enabled = 1;
+}
+
+/** @brief Suppress new connection activity */
+void disorder_eclient_disable_connect(disorder_eclient *c) {
+  c->enabled = 0;
+}
+
 /** @brief Return current state */
 unsigned long disorder_eclient_state(const disorder_eclient *c) {
   return c->statebits | (c->state > state_connected ? DISORDER_CONNECTED : 0);
@@ -340,9 +354,12 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) {
     /* If there is no password yet then we cannot connect */
     if(!config->password) {
       comms_error(c, "no password is configured");
+      c->enabled = 0;
       return;
     }
-    start_connect(c);
+    /* Only try to connect if enabled */
+    if(c->enabled)
+      start_connect(c);
     /* might now be state_disconnected (on error), state_connecting (slow
      * connect) or state_connected (fast connect).  If state_disconnected then
      * we just rely on a periodic callback from the event loop sometime. */
@@ -597,6 +614,7 @@ static void authuser_opcallback(disorder_eclient *c,
   if(c->rc / 100 != 2) {
     /* Wrong password or something.  We cannot proceed. */
     protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
+    c->enabled = 0;
     disorder_eclient_close(c);
     return;
   }
index efb6b2d87936d89303557dcc7232bcc89cf29878..6901961872bd848bcfd32ab94211c1133d048fe0 100644 (file)
@@ -483,7 +483,9 @@ int disorder_eclient_adduser(disorder_eclient *c,
                              const char *password,
                              const char *rights,
                              void *v);
-
+void disorder_eclient_enable_connect(disorder_eclient *c);
+void disorder_eclient_disable_connect(disorder_eclient *c);
+  
 #endif
 
 /*