- set_tool_colors(ql->menu);
- return vbox;
-}
-
-/* Popup menu items -------------------------------------------------------- */
-
-/** @brief Count the number of items selected */
-static int queue_count_selected(const struct queuelike *ql) {
- return hash_count(ql->selection);
-}
-
-/** @brief Count the number of items selected */
-static int queue_count_entries(const struct queuelike *ql) {
- int nitems = 0;
- const struct queue_entry *q;
-
- for(q = ql->q; q; q = q->next)
- ++nitems;
- return nitems;
-}
-
-/** @brief Count the number of items selected, excluding the playing track if
- * there is one */
-static int count_selected_nonplaying(const struct queuelike *ql) {
- int nselected = queue_count_selected(ql);
-
- if(ql->q == playing_track && selection_selected(ql->selection, ql->q->id))
- --nselected;
- return nselected;
-}
-
-/** @brief Determine whether the scratch option should be sensitive */
-static int scratch_sensitive(struct queuelike attribute((unused)) *ql,
- struct queue_menuitem attribute((unused)) *m,
- struct queue_entry attribute((unused)) *q) {
- /* We can scratch if the playing track is selected */
- return (playing_track
- && (disorder_eclient_state(client) & DISORDER_CONNECTED)
- && 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, scratch_completed, 0);
-}
-
-/** @brief Determine whether the remove option should be sensitive */
-static int remove_sensitive(struct queuelike *ql,
- struct queue_menuitem attribute((unused)) *m,
- struct queue_entry *q) {
- /* We can remove if we're hovering over a particular track or any non-playing
- * tracks are selected */
- return ((disorder_eclient_state(client) & DISORDER_CONNECTED)
- && ((q
- && q != playing_track)
- || 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) {
- const struct menuiteminfo *mii = user_data;
- struct queue_entry *q = mii->q;
- struct queuelike *ql = mii->ql;
-
- if(count_selected_nonplaying(mii->ql)) {
- /* 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, move_completed, 0);
- } else if(q)
- /* Remove just the hovered track */
- disorder_eclient_remove(client, q->id, remove_completed, 0);
-}
-
-/** @brief Determine whether the properties menu option should be sensitive */
-static int properties_sensitive(struct queuelike *ql,
- struct queue_menuitem attribute((unused)) *m,
- struct queue_entry attribute((unused)) *q) {
- /* "Properties" is sensitive if at least something is selected */
- return (hash_count(ql->selection) > 0
- && (disorder_eclient_state(client) & DISORDER_CONNECTED));
-}
-
-/** @brief Pop up properties for the selected tracks */
-static void properties_activate(GtkMenuItem attribute((unused)) *menuitem,
- gpointer user_data) {
- const struct menuiteminfo *mii = user_data;
-
- queue_properties(mii->ql);
-}
-
-/** @brief Determine whether the select all menu option should be sensitive */
-static int selectall_sensitive(struct queuelike *ql,
- struct queue_menuitem attribute((unused)) *m,
- struct queue_entry attribute((unused)) *q) {
- /* Sensitive if there is anything to select */
- return !!ql->q;
-}
-
-/** @brief Select all tracks */
-static void selectall_activate(GtkMenuItem attribute((unused)) *menuitem,
- gpointer user_data) {
- const struct menuiteminfo *mii = user_data;
- queue_select_all(mii->ql);
-}
-
-/** @brief Determine whether the select none menu option should be sensitive */
-static int selectnone_sensitive(struct queuelike *ql,
- struct queue_menuitem attribute((unused)) *m,
- struct queue_entry attribute((unused)) *q) {
- /* Sensitive if there is anything selected */
- return hash_count(ql->selection) != 0;
-}
-
-/** @brief Select no tracks */
-static void selectnone_activate(GtkMenuItem attribute((unused)) *menuitem,
- gpointer user_data) {
- const struct menuiteminfo *mii = user_data;
- queue_select_none(mii->ql);
-}
-
-/** @brief Determine whether the play menu option should be sensitive */
-static int play_sensitive(struct queuelike *ql,
- struct queue_menuitem attribute((unused)) *m,
- struct queue_entry attribute((unused)) *q) {
- /* "Play" is sensitive if at least something is selected */
- return (hash_count(ql->selection) > 0
- && (disorder_eclient_state(client) & DISORDER_CONNECTED));
-}
-
-/** @brief Play the selected tracks */
-static void play_activate(GtkMenuItem attribute((unused)) *menuitem,
- gpointer user_data) {
- const struct menuiteminfo *mii = user_data;
- struct queue_entry *q = mii->q;
- struct queuelike *ql = mii->ql;
-
- if(queue_count_selected(ql)) {
- /* Play selected tracks */
- for(q = ql->q; q; q = q->next)
- if(selection_selected(ql->selection, q->id))
- 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, play_completed, 0);
-}
-
-/* The queue --------------------------------------------------------------- */
-
-/** @brief Fix up the queue by sticking the currently playing track on the front */
-static struct queue_entry *fixup_queue(struct queue_entry *q) {
- D(("fixup_queue"));
- actual_queue = q;
- if(playing_track) {
- if(actual_queue)
- actual_queue->prev = playing_track;
- playing_track->next = actual_queue;
- return playing_track;
- } else
- return actual_queue;
-}
-
-/** @brief Adjust track played label
- *
- * Called regularly to adjust the so-far played label (redrawing the whole
- * queue once a second makes disobedience occupy >10% of the CPU on my Athlon
- * which is ureasonable expensive) */
-static gboolean adjust_sofar(gpointer attribute((unused)) data) {
- if(playing_length_label && playing_track)
- gtk_label_set_text(GTK_LABEL(playing_length_label),
- text_length(playing_track));
- return TRUE;
-}
-
-/** @brief Popup menu for the queue
- *
- * Properties first so that finger trouble is less dangerous. */
-static struct queue_menuitem queue_menu[] = {
- { "Track properties", properties_activate, properties_sensitive, 0, 0 },
- { "Select all tracks", selectall_activate, selectall_sensitive, 0, 0 },
- { "Deselect all tracks", selectnone_activate, selectnone_sensitive, 0, 0 },
- { "Scratch track", scratch_activate, scratch_sensitive, 0, 0 },
- { "Remove track from queue", remove_activate, remove_sensitive, 0, 0 },
- { 0, 0, 0, 0, 0 }
-};
-
-/** @brief Called whenever @ref DISORDER_PLAYING or @ref DISORDER_TRACK_PAUSED changes
- *
- * We monitor pause/resume as well as whether the track is playing in order to
- * keep the time played so far up to date correctly. See playing_completed().
- */
-static void playing_update(void attribute((unused)) *v) {
- D(("playing_update"));
- gtk_label_set_text(GTK_LABEL(report_label), "updating playing track");
- disorder_eclient_playing(client, playing_completed, 0);
-}
-
-/** @brief Create the queue widget */
-GtkWidget *queue_widget(void) {
- D(("queue_widget"));
- /* Arrange periodic update of the so-far played field */
- g_timeout_add(1000/*ms*/, adjust_sofar, 0);
- /* Arrange a callback whenever the playing state changes */
- register_monitor(playing_update, 0, DISORDER_PLAYING|DISORDER_TRACK_PAUSED);
- register_reset(queue_update);
- /* We pass choose_update() as our notify function since the choose screen
- * marks tracks that are playing/in the queue. */
- return queuelike(&ql_queue, fixup_queue, choose_update, queue_menu,
- maincolumns, NMAINCOLUMNS);
-}
-
-/** @brief Arrange an update of the queue widget
- *
- * Called when a track is added to the queue, removed from the queue (by user
- * cmmand or because it is to be played) or moved within the queue
- */
-void queue_update(void) {
- struct callbackdata *cbd;
-
- D(("queue_update"));
- cbd = xmalloc(sizeof *cbd);
- cbd->onerror = 0;
- cbd->u.ql = &ql_queue;
- gtk_label_set_text(GTK_LABEL(report_label), "updating queue");
- disorder_eclient_queue(client, queuelike_completed, cbd);
-}
-
-/* Recently played tracks -------------------------------------------------- */
-
-/** @brief Fix up the recently played list
- *
- * It's in the wrong order! TODO fix this globally */
-static struct queue_entry *fixup_recent(struct queue_entry *q) {
- struct queue_entry *qr = 0, *qn;
-
- D(("fixup_recent"));
- while(q) {
- qn = q->next;
- /* Swap next/prev pointers */
- q->next = q->prev;
- q->prev = qn;
- /* Remember last node for new head */
- qr = q;
- /* Next node */
- q = qn;