static void gtkclient_comms_error(void attribute((unused)) *u,
const char *msg) {
D(("gtkclient_comms_error %s", msg));
- /* Control buttons might have become unusable */
- control_update();
menu_update(-1);
gtk_label_set_text(GTK_LABEL(report_label), msg);
}
if(!msg)
/* We're idle - clear the report line */
gtk_label_set_text(GTK_LABEL(report_label), "");
- control_update();
menu_update(-1);
}
static gchar *format_volume(GtkScale *scale, gdouble value);
static gchar *format_balance(GtkScale *scale, gdouble value);
-static void control_monitor(void *u);
-
/* Control bar ------------------------------------------------------------- */
static int suppress_set_volume;
GtkAdjustment *volume_adj, *balance_adj;
+/** @brief Called whenever last_state changes in any way */
+static void control_monitor(void attribute((unused)) *u) {
+ int n;
+
+ D(("control_monitor"));
+ for(n = 0; n < NICONS; ++n)
+ icons[n].update(&icons[n]);
+}
+
/* Create the control bar */
GtkWidget *control_widget(void) {
GtkWidget *hbox = gtk_hbox_new(FALSE, 1), *vbox;
return hbox;
}
-/** @brief Update the control bar after some kind of state change */
-void control_update(void) {
+/** @brief Update the volume control when it changes */
+void volume_update(void) {
double l, r;
- D(("control_update"));
- /*control_monitor(0, disorder_eclient_state(client));*/
+ D(("volume_update"));
l = volume_l / 100.0;
r = volume_r / 100.0;
++suppress_set_volume;
--suppress_set_volume;
}
-static void control_monitor(void attribute((unused)) *u) {
- int n;
-
- for(n = 0; n < NICONS; ++n)
- icons[n].update(&icons[n]);
-}
-
/** @brief Update the state of one of the control icons
* @param icon Target icon
* @param visible True if this version of the button should be visible
if(!(client = gtkclient())
|| !(logclient = gtkclient()))
return 1; /* already reported an error */
- disorder_eclient_log(logclient, &log_callbacks, 0);
/* periodic operations (e.g. expiring the cache) */
#if MDEBUG || MTRACK
g_timeout_add(5000/*milliseconds*/, periodic, 0);
/* 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();
/* issue a NOP every so often */
g_timeout_add_full(G_PRIORITY_LOW,
1000/*interval, ms*/,
maybe_send_nop,
0/*data*/,
0/*notify*/);
+ /* Start monitoring the log */
+ disorder_eclient_log(logclient, &log_callbacks, 0);
D(("enter main loop"));
MTAG("misc");
g_main_loop_run(mainloop);
GtkWidget *control_widget(void);
/* Make the controls widget */
-void control_update(void);
-/* Called whenever we think the control widget needs changing */
-
+void volume_update(void);
+/* Called whenever we think the volume control has changed */
/* Queue/Recent */
playing_update();
queue_update();
recent_update();
- control_update();
+ volume_update();
}
static void log_connected(void attribute((unused)) *v) {
- struct callbackdata *cbd;
-
/* Don't know what we might have missed while disconnected so update
* everything. We get this at startup too and this is how we do the initial
* state fetch. */
all_update();
- /* Re-get the volume */
- cbd = xmalloc(sizeof *cbd);
- cbd->onerror = 0;
- disorder_eclient_volume(client, log_volume, -1, -1, cbd);
}
static void log_completed(void attribute((unused)) *v,
const char attribute((unused)) *track) {
playing = 0;
playing_update();
- control_update();
}
static void log_failed(void attribute((unused)) *v,
const char attribute((unused)) *status) {
playing = 0;
playing_update();
- control_update();
}
static void log_moved(void attribute((unused)) *v,
const char attribute((unused)) *user) {
playing = 1;
playing_update();
- control_update();
/* we get a log_removed() anyway so we don't need to update_queue() from
* here */
}
const char attribute((unused)) *user) {
playing = 0;
playing_update();
- control_update();
}
static void log_state(void attribute((unused)) *v,
unsigned long state) {
const struct monitor *m;
- const unsigned long changes = state ^ last_state;
-
- D(("log_state %s", disorder_eclient_interpret_state(state)));
+ unsigned long changes = state ^ last_state;
+ static int first = 1;
+
+ if(first) {
+ changes = -1UL;
+ first = 0;
+ }
+ D(("log_state old=%s new=%s changed=%s",
+ disorder_eclient_interpret_state(last_state),
+ disorder_eclient_interpret_state(state),
+ disorder_eclient_interpret_state(changes)));
last_state = state;
/* Tell anything that cares about the state change */
for(m = monitors; m; m = m->next) {
if(volume_l != l || volume_r != r) {
volume_l = l;
volume_r = r;
- control_update();
+ volume_update();
}
}
/* We'll need to resend all operations */
for(op = c->ops; op; op = op->next)
op->sent = 0;
+ /* Drop our use a hint that we're disconnected */
+ if(c->log_callbacks && c->log_callbacks->state)
+ c->log_callbacks->state(c->log_v, c->statebits);
}
/** @brief Return current state */
c->state = state_connected;
byte_xasprintf(&r, "connected to %s", c->ident);
c->callbacks->report(c->u, r);
+ /* If this is a log client we expect to get a bunch of updates from the
+ * server straight away */
}
}
* Once a client is being used for logging it cannot be used for anything else.
* There is magic in authuser_opcallback() to re-submit the @c log command
* after reconnection.
+ *
+ * NB that the @c state callback may be called from within this function,
+ * i.e. not solely later on from the event loop callback.
*/
int disorder_eclient_log(disorder_eclient *c,
const disorder_eclient_log_callbacks *callbacks,
if(c->log_callbacks) return -1;
c->log_callbacks = callbacks;
c->log_v = v;
+ /* Repoort initial state */
+ if(c->log_callbacks->state)
+ c->log_callbacks->state(c->log_v, c->statebits);
stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, v,
"log", (char *)0);
return 0;
#define NBITS (sizeof bits / sizeof *bits)
dynstr_init(d);
+ if(!statebits)
+ dynstr_append(d, '0');
for(n = 0; n < NBITS; ++n)
if(statebits & bits[n].bit) {
if(d->nvec)