Merge latest Disobedience work
authorRichard Kettlewell <rjk@greenend.org.uk>
Fri, 27 Nov 2009 20:19:30 +0000 (20:19 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Fri, 27 Nov 2009 20:19:30 +0000 (20:19 +0000)
disobedience/choose-menu.c
disobedience/disobedience.h
disobedience/help.c
disobedience/login.c
disobedience/manual/Makefile.am
disobedience/menu.c
disobedience/misc.c
disobedience/playlists.c
disobedience/properties.c
disobedience/users.c

index 44ad04f..61943d2 100644 (file)
 #include "popup.h"
 #include "choose.h"
 
+static void choose_playchildren_callback(GtkTreeModel *model,
+                                         GtkTreePath *path,
+                                         GtkTreeIter *iter,
+                                         gpointer data);
+static void choose_playchildren_received(void *v,
+                                         const char *err,
+                                         int nvec, char **vec);
+static void choose_playchildren_played(void *v, const char *err);
+
 /** @brief Popup menu */
 static GtkWidget *choose_menu;
 
@@ -210,6 +219,48 @@ static void choose_selectchildren_activate
                                       0);
 }
 
+/** @brief Play all children */
+static void choose_playchildren_activate
+    (GtkMenuItem attribute((unused)) *item,
+     gpointer attribute((unused)) userdata) {
+  /* Only one thing is selected */
+  gtk_tree_selection_selected_foreach(choose_selection,
+                                      choose_playchildren_callback,
+                                      0);
+}
+
+static void choose_playchildren_callback(GtkTreeModel attribute((unused)) *model,
+                                         GtkTreePath *path,
+                                         GtkTreeIter *iter,
+                                         gpointer attribute((unused)) data) {
+  /* Find the children and play them */
+  disorder_eclient_files(client, choose_playchildren_received,
+                         choose_get_track(iter),
+                         NULL/*re*/,
+                         NULL);
+  /* Expand the node */
+  gtk_tree_view_expand_row(GTK_TREE_VIEW(choose_view), path, FALSE);
+}
+
+static void choose_playchildren_received(void attribute((unused)) *v,
+                                         const char *err,
+                                         int nvec, char **vec) {
+  if(err) {
+    popup_protocol_error(0, err);
+    return;
+  }
+  for(int n = 0; n < nvec; ++n)
+    disorder_eclient_play(client, vec[n], choose_playchildren_played, NULL);
+}
+
+static void choose_playchildren_played(void attribute((unused)) *v,
+                                       const char *err) {
+  if(err) {
+    popup_protocol_error(0, err);
+    return;
+  }
+}
+
 /** @brief Pop-up menu for choose */
 static struct menuitem choose_menuitems[] = {
   {
@@ -234,6 +285,13 @@ static struct menuitem choose_menuitems[] = {
     0
   },
   {
+    "Play children",
+    choose_playchildren_activate,
+    choose_selectchildren_sensitive,    /* re-use */
+    0,
+    0
+  },
+  {
     "Deselect all tracks",
     choose_selectnone_activate,
     choose_selectnone_sensitive,
index 11da2c3..8ce1601 100644 (file)
@@ -85,6 +85,11 @@ struct button {
   void (*clicked)(GtkButton *button, gpointer userdata);
   const char *tip;
   GtkWidget *widget;
+  void (*pack)(GtkBox *box,
+               GtkWidget *child,
+               gboolean expand,
+               gboolean fill,
+               guint padding);
 };
 
 /* Variables --------------------------------------------------------------- */
@@ -228,7 +233,7 @@ void manage_users(void);
 
 /* Help */
 
-void popup_help(void);
+void popup_help(const char *what);
 
 /* RTP */
 
index 5ebe457..5b708e8 100644 (file)
 #include <unistd.h>
 
 /** @brief Display the manual page */
-void popup_help(void) {
+void popup_help(const char *what) {
   char *path;
   pid_t pid;
   int w;
 
-  byte_xasprintf(&path, "%s/index.html", dochtmldir);
+  if(!what)
+    what = "index.html";
+  byte_xasprintf(&path, "%s/%s", dochtmldir, what);
   if(!(pid = xfork())) {
     exitfn = _exit;
     if(!xfork()) {
index 36850c1..4031c3a 100644 (file)
@@ -254,13 +254,15 @@ static struct button buttons[] = {
     "Login",
     login_ok,
     "(Re-)connect using these settings",
-    0
+    0,
+    NULL,
   },
   {
     GTK_STOCK_CLOSE,
     login_cancel,
     "Discard changes and close window",
-    0
+    0,
+    NULL,
   },
 };
 
index bb86aa3..dd41929 100644 (file)
@@ -23,6 +23,8 @@ dochtml_DATA=index.html intro.html misc.html playlists.html           \
        choose-search.png choose.png disobedience-debian-menu.png       \
        disobedience-terminal.png disorder-email-confirm.png            \
        disorder-web-login.png login.png menu-control.png               \
-       menu-edit.png menu-help.png menu-server.png queue-menu.png      \
+       menu-edit.png menu-help.png menu-server.png                     \
+       playlist-create.png playlist-picker-menu.png                    \
+       playlist-popup-menu.png playlist-window.png queue-menu.png      \
        queue.png queue2.png recent.png track-properties.png            \
        volume-slider.png
index f04f720..86ea177 100644 (file)
@@ -134,7 +134,7 @@ static void manual_popup(gpointer attribute((unused)) callback_data,
                        GtkWidget attribute((unused)) *menu_item) {
   D(("manual_popup"));
 
-  popup_help();
+  popup_help(NULL);
 }
 
 /** @brief Called when version arrives, displays about... popup */
index 96e1750..41fcd13 100644 (file)
@@ -187,7 +187,14 @@ GtkWidget *create_buttons_box(struct button *buttons,
     gtk_widget_set_style(buttons[n].widget, tool_style);
     g_signal_connect(G_OBJECT(buttons[n].widget), "clicked",
                      G_CALLBACK(buttons[n].clicked), 0);
-    gtk_box_pack_start(GTK_BOX(box), buttons[n].widget, FALSE, FALSE, 1);
+    void (*pack)(GtkBox *box,
+                 GtkWidget *child,
+                 gboolean expand,
+                 gboolean fill,
+                 guint padding);
+    if(!(pack = buttons[n].pack))
+      pack = gtk_box_pack_start;
+    pack(GTK_BOX(box), buttons[n].widget, FALSE, FALSE, 1);
     gtk_widget_set_tooltip_text(buttons[n].widget, buttons[n].tip);
   }
   return box;
index b5520b9..1f836ad 100644 (file)
@@ -126,6 +126,11 @@ static void playlist_picker_delete_obsolete(GtkTreeIter parent[1],
 static gboolean playlist_picker_button(GtkWidget *widget,
                                        GdkEventButton *event,
                                        gpointer user_data);
+static gboolean playlist_editor_keypress(GtkWidget *widget,
+                                         GdkEventKey *event,
+                                         gpointer user_data);
+static void playlist_editor_ok(GtkButton *button, gpointer userdata);
+static void playlist_editor_help(GtkButton *button, gpointer userdata);
 
 /** @brief Playlist editing window */
 static GtkWidget *playlist_window;
@@ -875,13 +880,15 @@ static struct button playlist_picker_buttons[] = {
     GTK_STOCK_ADD,
     playlist_picker_add,
     "Create a new playlist",
-    0
+    0,
+    NULL,
   },
   {
     GTK_STOCK_REMOVE,
     playlist_picker_delete,
     "Delete a playlist",
-    0
+    0,
+    NULL,
   },
 };
 #define NPLAYLIST_PICKER_BUTTONS (sizeof playlist_picker_buttons / sizeof *playlist_picker_buttons)
@@ -1045,6 +1052,26 @@ static GtkWidget *playlist_editor_public;
 static GtkWidget *playlist_editor_private;
 static int playlist_editor_setting_buttons;
 
+/** @brief Buttons for the playlist window */
+static struct button playlist_editor_buttons[] = {
+  {
+    GTK_STOCK_OK,
+    playlist_editor_ok,
+    "Close window",
+    0,
+    gtk_box_pack_end,
+  },
+  {
+    GTK_STOCK_HELP,
+    playlist_editor_help,
+    "Go to manual",
+    0,
+    gtk_box_pack_end,
+  },
+};
+
+#define NPLAYLIST_EDITOR_BUTTONS (int)(sizeof playlist_editor_buttons / sizeof *playlist_editor_buttons)
+
 static GtkWidget *playlists_editor_create(void) {
   assert(ql_playlist.view == NULL);     /* better not be set up already */
 
@@ -1069,15 +1096,36 @@ static GtkWidget *playlists_editor_create(void) {
   gtk_box_pack_start(GTK_BOX(hbox), playlist_editor_private,
                      FALSE/*expand*/, FALSE/*fill*/, 0);
   playlist_editor_set_buttons(0,0,0);
+  create_buttons_box(playlist_editor_buttons,
+                     NPLAYLIST_EDITOR_BUTTONS,
+                     hbox);
 
   GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(vbox), init_queuelike(&ql_playlist),
+  GtkWidget *view = init_queuelike(&ql_playlist);
+  gtk_box_pack_start(GTK_BOX(vbox), view,
                      TRUE/*expand*/, TRUE/*fill*/, 0);
   gtk_box_pack_start(GTK_BOX(vbox), hbox,
                      FALSE/*expand*/, FALSE/*fill*/, 0);
+  g_signal_connect(view, "key-press-event",
+                   G_CALLBACK(playlist_editor_keypress), 0);
   return vbox;
 }
 
+static gboolean playlist_editor_keypress(GtkWidget attribute((unused)) *widget,
+                                         GdkEventKey *event,
+                                         gpointer attribute((unused)) user_data) {
+  if(event->state)
+    return FALSE;
+  switch(event->keyval) {
+  case GDK_BackSpace:
+  case GDK_Delete:
+    playlist_remove_activate(NULL, NULL);
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
 /** @brief Called when the public/private buttons are set */
 static void playlist_editor_button_toggled(GtkToggleButton *tb,
                                            gpointer userdata) {
@@ -1201,6 +1249,16 @@ static void playlists_editor_received_tracks(void *v,
   ql_new_queue(&ql_playlist, newq);
 }
 
+static void playlist_editor_ok(GtkButton attribute((unused)) *button, 
+                               gpointer attribute((unused)) userdata) {
+  gtk_widget_destroy(playlist_window);
+}
+
+static void playlist_editor_help(GtkButton attribute((unused)) *button, 
+                                 gpointer attribute((unused)) userdata) {
+  popup_help("playlists.html");
+}
+
 /* Playlist mutation -------------------------------------------------------- */
 
 /** @brief State structure for guarded playlist modification
index 092e8db..6600cf9 100644 (file)
@@ -46,6 +46,7 @@ static void prefdata_completed(void *v, const char *err, const char *value);
 static void properties_ok(GtkButton *button, gpointer userdata);
 static void properties_apply(GtkButton *button, gpointer userdata);
 static void properties_cancel(GtkButton *button, gpointer userdata);
+static void properties_help(GtkButton *button, gpointer userdata);
 
 static void properties_logged_in(const char *event,
                                  void *eventdata,
@@ -126,22 +127,32 @@ static const struct pref {
 /* Buttons that appear at the bottom of the window */
 static struct button buttons[] = {
   {
+    GTK_STOCK_HELP,
+    properties_help,
+    "Go to manual",
+    0,
+    gtk_box_pack_start,
+  },
+  {
     GTK_STOCK_OK,
     properties_ok,
     "Apply all changes and close window",
-    0
-  },
-  {
-    GTK_STOCK_APPLY,
-    properties_apply,
-    "Apply all changes and keep window open",
-    0
+    0,
+    gtk_box_pack_end,
   },
   {
     GTK_STOCK_CANCEL,
     properties_cancel,
     "Discard all changes and close window",
-    0
+    0,
+    gtk_box_pack_end
+  },
+  {
+    GTK_STOCK_APPLY,
+    properties_apply,
+    "Apply all changes and keep window open",
+    0,
+    gtk_box_pack_end,
   },
 };
 
@@ -490,6 +501,11 @@ static void properties_cancel(GtkButton attribute((unused)) *button,
   properties_event = 0;
 }
 
+static void properties_help(GtkButton attribute((unused)) *button,
+                            gpointer attribute((unused)) userdata) {
+  popup_help("properties.html");
+}
+
 /** @brief Called when we've just logged in
  *
  * Destroys the current properties window.
index 1d2a169..b078698 100644 (file)
@@ -660,13 +660,15 @@ static struct button users_buttons[] = {
     GTK_STOCK_ADD,
     users_add,
     "Create a new user",
-    0
+    0,
+    NULL,
   },
   {
     GTK_STOCK_REMOVE,
     users_delete,
     "Delete a user",
-    0
+    0,
+    NULL,
   },
 };
 #define NUSERS_BUTTONS (sizeof users_buttons / sizeof *users_buttons)