/* User actions ------------------------------------------------------------ */
+/** @brief Called when disorder_eclient_play completes */
+void play_completed(void attribute((unused)) *v,
+ const char *error) {
+ if(error)
+ popup_protocol_error(0, error);
+}
+
/** @brief Clicked on something
*
* This implements playing, all the modifiers for selection, etc.
clear_selection(root);
set_selection(cn, 1);
gtk_label_set_text(GTK_LABEL(report_label), "adding track to queue");
- disorder_eclient_play(client, cn->path, 0, 0);
+ disorder_eclient_play(client, cn->path, play_completed, 0);
last_click = 0;
}
} else if(event->type == GDK_BUTTON_PRESS
gtk_label_set_text(GTK_LABEL(report_label), "adding track to queue");
for(n = 0; tracks[n]; ++n)
- disorder_eclient_play(client, tracks[n], 0, 0);
+ disorder_eclient_play(client, tracks[n], play_completed, 0);
}
/** @brief Called when the menu's properties option is activated */
gtk_label_set_text(GTK_LABEL(report_label), "adding track to queue");
for(n = 0; n < ntracks; ++n)
- disorder_eclient_play(client, tracks[n], 0, 0);
+ disorder_eclient_play(client, tracks[n], play_completed, 0);
}
static void properties_dir(struct choosenode *cn,
update_icon(icon, visible, usable);
}
+static void icon_action_completed(void attribute((unused)) *v,
+ const char *error) {
+ if(error)
+ popup_protocol_error(0, error);
+}
+
static void clicked_icon(GtkButton attribute((unused)) *button,
gpointer userdata) {
const struct icon *icon = userdata;
if(!suppress_actions)
- icon->action(client, 0, 0);
+ icon->action(client, icon_action_completed, 0);
}
static void clicked_menu(GtkMenuItem attribute((unused)) *menuitem,
const struct icon *icon = userdata;
if(!suppress_actions)
- icon->action(client, 0, 0);
+ icon->action(client, icon_action_completed, 0);
}
static void toggled_menu(GtkCheckMenuItem *menuitem,
&& !!(icons[n].flags & ICON_INACTIVE) == !!menuitem->active)
break;
if(n < NICONS)
- icons[n].action(client, 0, 0);
+ icons[n].action(client, icon_action_completed, 0);
}
/** @brief Called when the volume has been adjusted */
}
/** @brief Called when a NOP completes */
-static void nop_completed(void attribute((unused)) *v) {
+static void nop_completed(void attribute((unused)) *v,
+ const char attribute((unused)) *error) {
+ /* TODO report the error somewhere */
nop_in_flight = 0;
}
#include "configuration.h"
#include "hash.h"
#include "selection.h"
+#include "kvp.h"
#include <glib.h>
#include <gtk/gtk.h>
const char *part);
/* Called when a namepart might have changed */
-
/* Choose */
GtkWidget *choose_widget(void);
void choose_update(void);
/* Called when we think the choose tree might need updating */
+void play_completed(void *v,
+ const char *error);
+
/* Login details */
void login_box(void);
static const char *get_edited_namepart(struct prefdata *f);
static void set_edited_namepart(struct prefdata *f, const char *value);
static void set_namepart(struct prefdata *f, const char *value);
-static void set_namepart_completed(void *v);
+static void set_namepart_completed(void *v, const char *error);
static void kickoff_string(struct prefdata *f);
static void completed_string(struct prefdata *f);
static void set_namepart(struct prefdata *f, const char *value) {
char *s;
- struct callbackdata *cbd = xmalloc(sizeof *cbd);
- cbd->u.f = f;
byte_xasprintf(&s, "trackname_display_%s", f->p->part);
/* We don't know what the default is so can never unset. This is a bug
* relative to the original design, which is supposed to only ever allow for
* non-trivial namepart preferences. I suppose the server could spot a
* default being set and translate it into an unset. */
disorder_eclient_set(client, set_namepart_completed, f->track, s, value,
- cbd);
+ f);
}
/* Called when we've set a namepart */
-static void set_namepart_completed(void *v) {
- struct callbackdata *cbd = v;
- struct prefdata *f = cbd->u.f;
-
- namepart_update(f->track, "display", f->p->part);
+static void set_namepart_completed(void *v, const char *error) {
+ if(error)
+ popup_protocol_error(0, error);
+ else {
+ struct prefdata *f = v;
+
+ namepart_update(f->track, "display", f->p->part);
+ }
}
/* String preferences ------------------------------------------------------ */
gtk_entry_set_text(GTK_ENTRY(f->widget), value);
}
+static void set_string_completed(void attribute((unused)) *v,
+ const char *error) {
+ if(error)
+ popup_protocol_error(0, error);
+}
+
static void set_string(struct prefdata *f, const char *value) {
- if(strcmp(f->p->default_value, value))
- /* Different from default, set it */
- disorder_eclient_set(client, 0/*completed*/, f->track, f->p->part,
- value, 0/*v*/);
- else
- /* Same as default, just unset */
- disorder_eclient_unset(client, 0/*completed*/, f->track, f->p->part,
- 0/*v*/);
+ disorder_eclient_set(client, set_string_completed, f->track, f->p->part,
+ value, 0/*v*/);
}
/* Boolean preferences ----------------------------------------------------- */
strcmp(value, "0"));
}
+#define set_boolean_completed set_string_completed
+
static void set_boolean(struct prefdata *f, const char *value) {
char *s;
byte_xasprintf(&s, "trackname_display_%s", f->p->part);
- if(strcmp(value, f->p->default_value))
- disorder_eclient_set(client, 0/*completed*/, f->track, f->p->part, value,
- 0/*v*/);
- else
- /* If default value then delete the pref */
- disorder_eclient_unset(client, 0/*completed*/, f->track, f->p->part,
- 0/*v*/);
+ disorder_eclient_set(client, set_boolean_completed,
+ f->track, f->p->part, value, 0/*v*/);
}
/* Querying preferences ---------------------------------------------------- */
return q;
}
+static void move_completed(void attribute((unused)) *v,
+ const char *error) {
+ if(error)
+ popup_protocol_error(0, error);
+}
+
/** @brief Called when data is dropped */
static gboolean queue_drag_drop(GtkWidget attribute((unused)) *widget,
GdkDragContext *drag_context,
if(q != playing_track && selection_selected(ql->selection, q->id))
vector_append(&vec, (char *)q->id);
disorder_eclient_moveafter(client, id, vec.nvec, (const char **)vec.vec,
- 0/*completed*/, 0/*v*/);
+ move_completed, 0/*v*/);
gtk_drag_finish(drag_context, TRUE, TRUE, when);
/* Destroy dropzones */
remove_drag_targets(ql);
&& selection_selected(ql->selection, playing_track->id));
}
+/** @brief Called when disorder_eclient_scratch completes */
+static void scratch_completed(void attribute((unused)) *v,
+ const char *error) {
+ if(error)
+ popup_protocol_error(0, error);
+}
+
/** @brief Scratch the playing track */
static void scratch_activate(GtkMenuItem attribute((unused)) *menuitem,
gpointer attribute((unused)) user_data) {
if(playing_track)
- disorder_eclient_scratch(client, playing_track->id, 0, 0);
+ disorder_eclient_scratch(client, playing_track->id, scratch_completed, 0);
}
/** @brief Determine whether the remove option should be sensitive */
|| count_selected_nonplaying(ql)));
}
+static void remove_completed(void attribute((unused)) *v,
+ const char *error) {
+ if(error)
+ popup_protocol_error(0, error);
+}
+
/** @brief Remove selected track(s) */
static void remove_activate(GtkMenuItem attribute((unused)) *menuitem,
gpointer user_data) {
/* Remove selected tracks */
for(q = ql->q; q; q = q->next)
if(selection_selected(ql->selection, q->id) && q != playing_track)
- disorder_eclient_remove(client, q->id, 0, 0);
+ disorder_eclient_remove(client, q->id, move_completed, 0);
} else if(q)
/* Remove just the hovered track */
- disorder_eclient_remove(client, q->id, 0, 0);
+ disorder_eclient_remove(client, q->id, remove_completed, 0);
}
/** @brief Determine whether the properties menu option should be sensitive */
/* Play selected tracks */
for(q = ql->q; q; q = q->next)
if(selection_selected(ql->selection, q->id))
- disorder_eclient_play(client, q->track, 0, 0);
+ disorder_eclient_play(client, q->track, play_completed, 0);
} else if(q)
/* Nothing is selected, so play the hovered track */
- disorder_eclient_play(client, q->track, 0, 0);
+ disorder_eclient_play(client, q->track, play_completed, 0);
}
/* The queue --------------------------------------------------------------- */
return r;
}
-/** @brief Called when various things fail */
-static void users_op_failed(struct callbackdata attribute((unused)) *cbd,
- int attribute((unused)) code,
- const char *msg) {
- popup_submsg(users_window, GTK_MESSAGE_ERROR, msg);
+/** @brief Called when a user setting has been edited */
+static void users_edituser_completed(void attribute((unused)) *v,
+ const char *error) {
+ if(error)
+ popup_submsg(users_window, GTK_MESSAGE_ERROR, error);
}
/** @brief Called when a new user has been created */
-static void users_adduser_completed(void *v) {
- struct callbackdata *cbd = v;
-
- /* Now the user is created we can go ahead and set the email address */
- if(*cbd->u.edituser.email) {
- struct callbackdata *ncbd = xmalloc(sizeof *cbd);
- ncbd->onerror = users_op_failed;
- disorder_eclient_edituser(client, NULL, cbd->u.edituser.user,
- "email", cbd->u.edituser.email, ncbd);
+static void users_adduser_completed(void *v,
+ const char *error) {
+ if(error) {
+ popup_submsg(users_window, GTK_MESSAGE_ERROR, error);
+ mode(ADD); /* Let the user try again */
+ } else {
+ const struct kvp *const kvp = v;
+ const char *user = kvp_get(kvp, "user");
+ const char *email = kvp_get(kvp, "email"); /* maybe NULL */
+
+ /* Now the user is created we can go ahead and set the email address */
+ if(email)
+ disorder_eclient_edituser(client, users_edituser_completed, user,
+ "email", email, NULL);
+ /* Refresh the list of users */
+ disorder_eclient_users(client, users_got_list, 0);
+ /* We'll select the newly created user */
+ users_deferred_select = user;
}
- /* Refresh the list of users */
- disorder_eclient_users(client, users_got_list, 0);
- /* We'll select the newly created user */
- users_deferred_select = cbd->u.edituser.user;
-}
-
-/** @brief Called if creating a new user fails */
-static void users_adduser_failed(struct callbackdata attribute((unused)) *cbd,
- int attribute((unused)) code,
- const char *msg) {
- popup_submsg(users_window, GTK_MESSAGE_ERROR, msg);
- mode(ADD); /* Let the user try again */
}
/** @brief Called when the 'Apply' button is pressed */
static void users_apply(GtkButton attribute((unused)) *button,
gpointer attribute((unused)) userdata) {
- struct callbackdata *cbd;
const char *password;
const char *password2;
const char *name;
popup_submsg(users_window, GTK_MESSAGE_ERROR, "Invalid email address");
return;
}
- cbd = xmalloc(sizeof *cbd);
- cbd->onerror = users_adduser_failed;
- cbd->u.edituser.user = name;
- cbd->u.edituser.email = email;
- disorder_eclient_adduser(client, users_adduser_completed,
+ disorder_eclient_adduser(client,
+ users_adduser_completed,
name,
password,
rights_string(users_get_rights()),
- cbd);
+ kvp_make("user", name,
+ "email", email,
+ (char *)0));
/* We switch to no-op mode while creating the user */
mode(NONE);
break;
popup_submsg(users_window, GTK_MESSAGE_ERROR, "Invalid email address");
return;
}
- cbd = xmalloc(sizeof *cbd);
- cbd->onerror = users_op_failed;
- disorder_eclient_edituser(client, NULL, users_selected,
- "email", email, cbd);
- disorder_eclient_edituser(client, NULL, users_selected,
- "password", password, cbd);
- disorder_eclient_edituser(client, NULL, users_selected,
- "rights", rights_string(users_get_rights()), cbd);
+ disorder_eclient_edituser(client, users_edituser_completed, users_selected,
+ "email", email, NULL);
+ disorder_eclient_edituser(client, users_edituser_completed, users_selected,
+ "password", password, NULL);
+ disorder_eclient_edituser(client, users_edituser_completed, users_selected,
+ "rights", rights_string(users_get_rights()), NULL);
/* We remain in edit mode */
break;
}
}
/** @brief Called when a user has been deleted */
-static void users_deleted(void *v) {
- const struct callbackdata *const cbd = v;
- GtkTreeIter iter[1];
-
- if(!users_find_user(cbd->u.user, iter)) /* Find the user... */
- gtk_list_store_remove(users_list, iter); /* ...and remove them */
+static void users_delete_completed(void *v,
+ const char *error) {
+ if(error)
+ popup_submsg(users_window, GTK_MESSAGE_ERROR, error);
+ else {
+ const struct kvp *const kvp = v;
+ const char *const user = kvp_get(kvp, "user");
+ GtkTreeIter iter[1];
+
+ if(!users_find_user(user, iter)) /* Find the user... */
+ gtk_list_store_remove(users_list, iter); /* ...and remove them */
+ }
}
/** @brief Called when the 'Delete' button is pressed */
gpointer attribute((unused)) userdata) {
GtkWidget *yesno;
int res;
- struct callbackdata *cbd;
if(!users_selected)
return;
res = gtk_dialog_run(GTK_DIALOG(yesno));
gtk_widget_destroy(yesno);
if(res == GTK_RESPONSE_YES) {
- cbd = xmalloc(sizeof *cbd);
- cbd->onerror = users_op_failed;
- cbd->u.user = users_selected;
- disorder_eclient_deluser(client, users_deleted, cbd->u.user, cbd);
+ disorder_eclient_deluser(client, users_delete_completed, users_selected,
+ kvp_make("user", users_selected,
+ (char *)0));
}
}
/* for commands with no response */
static void no_response_opcallback(disorder_eclient *c,
struct operation *op) {
+ disorder_eclient_no_response *completed
+ = (disorder_eclient_no_response *)op->completed;
+
D(("no_response_callback"));
- if(c->rc / 100 == 2) {
- if(op->completed)
- ((disorder_eclient_no_response *)op->completed)(op->v);
- } else
- /* TODO don't use protocol_error here */
- protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
+ if(c->rc / 100 == 2)
+ completed(op->v, NULL);
+ else
+ completed(op->v, errorstring(c));
}
/* error callback for queue_unmarshall */
* It is always allowed for these to be null pointers if you don't care about
* the result. */
-typedef void disorder_eclient_no_response(void *v);
-/* completion callback with no data */
+/** @brief Trivial completion callback
+ * @param v User data
+ * @param error Error string or NULL on succes
+ */
+typedef void disorder_eclient_no_response(void *v,
+ const char *error);
/** @brief String result completion callback
* @param v User data