- /* Titles */
- x = 0;
- for(col = 0; col < ql->ncolumns; ++col) {
- gtk_widget_set_size_request(GTK_BIN(ql->titlecells[col])->child,
- maxwidths[col], -1);
- gtk_layout_move(GTK_LAYOUT(ql->titlelayout), ql->titlecells[col], x, 0);
- x += maxwidths[col];
- }
- gtk_widget_set_size_request(GTK_BIN(ql->titlecells[col])->child,
- totalwidth - x, -1);
- gtk_layout_move(GTK_LAYOUT(ql->titlelayout), ql->titlecells[col], x, 0);
- /* Set the states */
- set_widget_states(ql);
- /* Make sure it's all visible */
- gtk_widget_show_all(ql->mainlayout);
- gtk_widget_show_all(ql->titlelayout);
- /* Layouts might shrink to arrange for the area they shrink out of to be
- * redrawn */
- gtk_widget_queue_draw(ql->mainlayout);
- gtk_widget_queue_draw(ql->titlelayout);
- /* Adjust the size of the layout */
- gtk_layout_set_size(GTK_LAYOUT(ql->mainlayout), x, y);
- gtk_layout_set_size(GTK_LAYOUT(ql->titlelayout), x, titlerowheight);
- gtk_widget_set_size_request(ql->titlelayout, -1, titlerowheight);
-}
-
-/** @brief Called with new queue/recent contents */
-static void queuelike_completed(void *v,
- const char *error,
- struct queue_entry *q) {
- if(error)
- popup_protocol_error(0, error);
- else {
- struct queuelike *const ql = v;
-
- D(("queuelike_complete"));
- /* Install the new queue */
- update_queue(ql, ql->fixup ? ql->fixup(q) : q);
- /* Update the display */
- redisplay_queue(ql);
- if(ql->notify)
- ql->notify();
- /* Update sensitivity of main menu items */
- menu_update(-1);
- }
-}
-
-/** @brief Called with a new currently playing track */
-static void playing_completed(void attribute((unused)) *v,
- const char *error,
- struct queue_entry *q) {
- if(error)
- popup_protocol_error(0, error);
- else {
- D(("playing_completed"));
- playing_track = q;
- /* Record when we got the playing track data so we know how old the 'sofar'
- * field is */
- time(&last_playing);
- queuelike_completed(&ql_queue, 0, actual_queue);
- }
-}
-
-/** @brief Called when the queue is scrolled */
-static void queue_scrolled(GtkAdjustment *adjustment,
- gpointer user_data) {
- GtkAdjustment *titleadj = user_data;
-
- D(("queue_scrolled"));
- gtk_adjustment_set_value(titleadj, adjustment->value);
-}
-
-/** @brief Create a queuelike thing (queue/recent) */
-static GtkWidget *queuelike(struct queuelike *ql,
- struct queue_entry *(*fixup)(struct queue_entry *),
- void (*notify)(void),
- struct queue_menuitem *menuitems,
- const struct column *columns,
- int ncolumns) {
- GtkWidget *vbox, *mainscroll, *titlescroll, *label;
- GtkAdjustment *mainadj, *titleadj;
- int col, n;
-
- D(("queuelike"));
- ql->fixup = fixup;
- ql->notify = notify;
- ql->menuitems = menuitems;
- ql->mainrowheight = !0; /* else division by 0 */
- ql->selection = selection_new();
- ql->columns = columns;
- ql->ncolumns = ncolumns;
- /* Create the layouts */
- NW(layout);
- ql->mainlayout = gtk_layout_new(0, 0);
- gtk_widget_set_style(ql->mainlayout, layout_style);
- NW(layout);
- ql->titlelayout = gtk_layout_new(0, 0);
- gtk_widget_set_style(ql->titlelayout, title_style);
- /* Scroll the layouts */
- ql->mainscroll = mainscroll = scroll_widget(ql->mainlayout);
- titlescroll = scroll_widget(ql->titlelayout);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(titlescroll),
- GTK_POLICY_NEVER, GTK_POLICY_NEVER);
- mainadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(mainscroll));
- titleadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(titlescroll));
- g_signal_connect(mainadj, "changed", G_CALLBACK(queue_scrolled), titleadj);
- g_signal_connect(mainadj, "value-changed", G_CALLBACK(queue_scrolled), titleadj);
- /* Fill the titles and put them anywhere */
- for(col = 0; col < ql->ncolumns; ++col) {
- NW(label);
- label = gtk_label_new(ql->columns[col].name);
- gtk_misc_set_alignment(GTK_MISC(label), ql->columns[col].xalign, 0);
- ql->titlecells[col] = wrap_queue_cell(label, title_style, 0);
- gtk_layout_put(GTK_LAYOUT(ql->titlelayout), ql->titlecells[col], 0, 0);
- }
- ql->titlecells[col] = get_padding_cell(title_style);
- gtk_layout_put(GTK_LAYOUT(ql->titlelayout), ql->titlecells[col], 0, 0);
- /* Pack the lot together in a vbox */
- NW(vbox);
- vbox = gtk_vbox_new(0, 0);
- gtk_box_pack_start(GTK_BOX(vbox), titlescroll, 0, 0, 0);
- gtk_box_pack_start(GTK_BOX(vbox), mainscroll, 1, 1, 0);
- /* Create the popup menu */
- NW(menu);
- ql->menu = gtk_menu_new();
- g_signal_connect(ql->menu, "destroy",
- G_CALLBACK(gtk_widget_destroyed), &ql->menu);
- for(n = 0; menuitems[n].name; ++n) {
- NW(menu_item);
- menuitems[n].w = gtk_menu_item_new_with_label(menuitems[n].name);
- gtk_menu_attach(GTK_MENU(ql->menu), menuitems[n].w, 0, 1, n, n + 1);
- }
- g_object_set_data(G_OBJECT(vbox), "type", (void *)&tabtype_queue);
- g_object_set_data(G_OBJECT(vbox), "queue", ql);
- /* Catch button presses */
- g_signal_connect(ql->mainlayout, "button-release-event",
- G_CALLBACK(mainlayout_button), ql);
-#if 0
- g_signal_connect(ql->mainlayout, "button-press-event",
- G_CALLBACK(mainlayout_button), ql);
-#endif
- 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);