+/* Directory menu items ---------------------------------------------------- */
+
+/** @brief Return the file children of @p cn
+ *
+ * The list is terminated by a null pointer.
+ */
+static const char **dir_files(struct choosenode *cn, int *nfiles) {
+ const char **files = xcalloc(cn->children.nvec + 1, sizeof (char *));
+ int n, m;
+
+ for(n = m = 0; n < cn->children.nvec; ++n)
+ if(!(cn->children.vec[n]->flags & CN_EXPANDABLE))
+ files[m++] = cn->children.vec[n]->path;
+ files[m] = 0;
+ if(nfiles) *nfiles = m;
+ return files;
+}
+
+static void play_dir(struct choosenode *cn,
+ void attribute((unused)) *wfu) {
+ int ntracks, n;
+ const char **tracks = dir_files(cn, &ntracks);
+
+ 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);
+}
+
+static void properties_dir(struct choosenode *cn,
+ void attribute((unused)) *wfu) {
+ int ntracks;
+ const char **tracks = dir_files(cn, &ntracks);
+
+ properties(ntracks, tracks);
+}
+
+static void select_dir(struct choosenode *cn,
+ void attribute((unused)) *wfu) {
+ int n;
+
+ clear_selection(root);
+ for(n = 0; n < cn->children.nvec; ++n)
+ set_selection(cn->children.vec[n], 1);
+}
+
+/** @brief Ensure @p cn is expanded and then call @p callback */
+static void call_with_dir(struct choosenode *cn,
+ when_filled_callback *whenfilled,
+ void *wfu) {
+ if(!(cn->flags & CN_EXPANDABLE))
+ return; /* something went wrong */
+ if(cn->flags & CN_EXPANDED)
+ /* @p cn is already open */
+ whenfilled(cn, wfu);
+ else {
+ /* @p cn is not open, arrange for the callback to go off when it is
+ * opened */
+ cn->whenfilled = whenfilled;
+ cn->wfu = wfu;
+ expand_node(cn, 0/*not contingnet upon search*/);
+ }
+}
+
+/** @brief Called when the directory menu's play option is activated */
+static void activate_dir_play(GtkMenuItem attribute((unused)) *menuitem,
+ gpointer user_data) {
+ struct choosenode *const cn = (struct choosenode *)user_data;
+
+ call_with_dir(cn, play_dir, 0);
+}
+
+/** @brief Called when the directory menu's properties option is activated */
+static void activate_dir_properties(GtkMenuItem attribute((unused)) *menuitem,
+ gpointer user_data) {
+ struct choosenode *const cn = (struct choosenode *)user_data;
+
+ call_with_dir(cn, properties_dir, 0);
+}
+
+/** @brief Called when the directory menu's select option is activated */
+static void activate_dir_select(GtkMenuItem attribute((unused)) *menuitem,
+ gpointer user_data) {
+ struct choosenode *const cn = (struct choosenode *)user_data;
+
+ call_with_dir(cn, select_dir, 0);
+}
+
+/** @brief Determine whether the directory menu's play option should be sensitive */
+static gboolean sensitive_dir_play(struct choosenode attribute((unused)) *cn) {
+ return !!(disorder_eclient_state(client) & DISORDER_CONNECTED);
+}
+
+/** @brief Determine whether the directory menu's properties option should be sensitive */
+static gboolean sensitive_dir_properties(struct choosenode attribute((unused)) *cn) {
+ return !!(disorder_eclient_state(client) & DISORDER_CONNECTED);